• Home /
  • comp /
  • arch /
  • Language design issue: reference types, or pass-by-reference?...

Delete / Löschen
Charlie Dawson
17.06.2009 - 14:36

Language design issue: reference types, or pass-by-reference?

[Sorry about the list of groups - is there anywhere more relevant,
excepting comp.compilers?]

I've got a fairly simple domain-specific language for engineers (*not*
programmers), which has functions, and which exclusively uses
pass-by-value.

Problem: I've just had to add a complex new stream type. I can't pass
objects of this type to functions by value, because of an
implementation issue; it also wouldn't make much sense, because I
would then be creating multiple objects that shared file state.
However, pass-by-reference is trivial.

The obvious fix is to prohibit pass-by-value in some way. Any thoughts
on the best way to do this? There are two obvious ways to do this, but
I can't make up my mind which is best. Comments welcome.

#1: a Java-style solution: define the new type to be a reference type.
This is nice and simple, and is transparent to the user. However, this
does restrict me if I decide in future that I want to add
pass-by-reference as well as pass-by-value; having a reference type,
*and* pass-by-reference semantics, may just cause confusion to the
user.

#2: a C++-style solution: add pass-by-reference semantics; the user is
forced to add an '&' character, or whatever, to a formal to specify
that it's passed by reference. This is complex, for a couple of
reasons: there's some busywork in semantic checking, but the real
issue is how I handle structures and arrays containing these new
objects. Having said that, I think it's sufficient to force the user
to add the '&' anywhere an object of the new type can appear:
structure definitions, array declarations, function parameters,
function return values.

The Java solution is simpler, but I can't help feeling that it's not
the right way to do references. It feels like a bodge.

Thanks

-Charlie

Michael Ekstrand
17.06.2009 - 15:41
Charlie Dawson <cd4573@yahoo.com> writes:
[Sorry about the list of groups - is there anywhere more relevant,
excepting comp.compilers?]

I've got a fairly simple domain-specific language for engineers (*not*
programmers), which has functions, and which exclusively uses
pass-by-value.

Problem: I've just had to add a complex new stream type. I can't pass
objects of this type to functions by value, because of an
implementation issue; it also wouldn't make much sense, because I
would then be creating multiple objects that shared file state.
However, pass-by-reference is trivial.

The obvious fix is to prohibit pass-by-value in some way. Any thoughts
on the best way to do this? There are two obvious ways to do this, but
I can't make up my mind which is best. Comments welcome.

#1: a Java-style solution: define the new type to be a reference type.
This is nice and simple, and is transparent to the user. However, this
does restrict me if I decide in future that I want to add
pass-by-reference as well as pass-by-value; having a reference type,
*and* pass-by-reference semantics, may just cause confusion to the
user.

#2: a C++-style solution: add pass-by-reference semantics; the user is
forced to add an '&' character, or whatever, to a formal to specify
that it's passed by reference. This is complex, for a couple of
reasons: there's some busywork in semantic checking, but the real
issue is how I handle structures and arrays containing these new
objects. Having said that, I think it's sufficient to force the user
to add the '&' anywhere an object of the new type can appear:
structure definitions, array declarations, function parameters,
function return values.

The Java solution is simpler, but I can't help feeling that it's not
the right way to do references. It feels like a bodge.

I tend to prefer the Java solution.

The C++ solution does have some elegance; however, the lack of syntax
indicating pass-by-reference at the call site means that it is not
obvious when a function call may modify one of its parameters. For an
I/O type, this is not really a problem; it can introduce difficulty when
the parameter in question is some data type such as int. C's pointers
instead of references get around this with the '&' syntax appearing in
the call; it makes it obvious that the function may modify the
parameter.

Going with the Java-style reference types (also used in many other
languages such as Python) does not have this problem, as it establishes
the general policy that mutable objects may be modified but that
functions cannot change the values of the variables the caller provided
as their arguments.

F'ups set to comp.programming, as this seems somewhat more relevant
there.

- Michael

--
mouse, n: A device for pointing at the xterm in which you want to type.

Ben Bacarisse
17.06.2009 - 16:24
Charlie Dawson <cd4573@yahoo.com> writes:

[Sorry about the list of groups - is there anywhere more relevant,
excepting comp.compilers?]

I've got a fairly simple domain-specific language for engineers (*not*
programmers), which has functions, and which exclusively uses
pass-by-value.

Problem: I've just had to add a complex new stream type. I can't pass
objects of this type to functions by value, because of an
implementation issue; it also wouldn't make much sense, because I
would then be creating multiple objects that shared file state.
However, pass-by-reference is trivial.

The obvious fix is to prohibit pass-by-value in some way. Any thoughts
on the best way to do this? There are two obvious ways to do this, but
I can't make up my mind which is best. Comments welcome.

#1: a Java-style solution: define the new type to be a reference type.
This is nice and simple, and is transparent to the user. However, this
does restrict me if I decide in future that I want to add
pass-by-reference as well as pass-by-value; having a reference type,
*and* pass-by-reference semantics, may just cause confusion to the
user.

#2: a C++-style solution: add pass-by-reference semantics; the user is
forced to add an '&' character, or whatever, to a formal to specify
that it's passed by reference. This is complex, for a couple of
reasons: there's some busywork in semantic checking, but the real
issue is how I handle structures and arrays containing these new
objects. Having said that, I think it's sufficient to force the user
to add the '&' anywhere an object of the new type can appear:
structure definitions, array declarations, function parameters,
function return values.

The Java solution is simpler, but I can't help feeling that it's not
the right way to do references. It feels like a bodge.

I don't know Java that well but I call what you describe as the Java
way the Algol-68 way and, at least there, it is not a bodge at all.
The key for Algol-68 was to define the contexts in which a reference
gets dereferenced so that it is automatic. Algol-68 does variables
like this. A (modifiable) variable is a name bound to reference to a
location (you get to choose how it is allocated) that is derefernced
on use. Of course, if you have variables already you will probably be
doing them differently, so in that sense it may come out less cleanly.

You then need one call mechanism (by value) but it is harder to outlaw
pass by value for objects where that is unhelpful. When a ref is used
to initialise a plain argument the effect is that of copying the value
referenced rather than a type-error. I can't remember if Algol-68 had
a way to prevent accidental pass by value. Obviously, when argument
is itself a ref the effect is to initialise one ref with another ref.

--
Ben.


"BartC"
17.06.2009 - 22:46

"Charlie Dawson" <cd4573@yahoo.com> wrote in message
news:eslh351e7lveo71ffgfqati4l348cn0i9a@4ax.com...
[Sorry about the list of groups - is there anywhere more relevant,
excepting comp.compilers?]

comp.lang.misc

I've got a fairly simple domain-specific language for engineers (*not*
programmers), which has functions, and which exclusively uses
pass-by-value.

Problem: I've just had to add a complex new stream type. I can't pass
objects of this type to functions by value, because of an
implementation issue; it also wouldn't make much sense, because I
would then be creating multiple objects that shared file state.
However, pass-by-reference is trivial.

The obvious fix is to prohibit pass-by-value in some way. Any thoughts
on the best way to do this? There are two obvious ways to do this, but
I can't make up my mind which is best. Comments welcome.

I might be missing something here, but why not define the complex type as a
handle? Then you can pass by value, and while there might be two copies of
the handle, the data itself (the stream or whatever) is not duplicated.

(The handle itself will be a pointer to some structure, or an index or key
to a table, whatever is necessary to identify the data)

Of course if you want these types to behave like full value-types elsewhere,
this would cause problems. More information about what can be done with
these types is needed.

--
Bart


Jon Harrop
17.06.2009 - 23:17
Charlie Dawson wrote:
#1: a Java-style solution: define the new type to be a reference type.
This is nice and simple, and is transparent to the user. However, this
does restrict me if I decide in future that I want to add
pass-by-reference as well as pass-by-value; having a reference type,
*and* pass-by-reference semantics, may just cause confusion to the
user.

#2: a C++-style solution: add pass-by-reference semantics; the user is
forced to add an '&' character, or whatever, to a formal to specify
that it's passed by reference. This is complex, for a couple of
reasons: there's some busywork in semantic checking, but the real
issue is how I handle structures and arrays containing these new
objects. Having said that, I think it's sufficient to force the user
to add the '&' anywhere an object of the new type can appear:
structure definitions, array declarations, function parameters,
function return values.

#3: The .NET way. Have both value types and references types.

The Java solution is simpler, but I can't help feeling that it's not
the right way to do references. It feels like a bodge.

C++ is the botch. You probably don't want to borrow any language features
from C++, particularly if you want to target non-programmers, i.e. people
who cannot afford to waste enormous amount of time learning endless numbers
of workarounds for deficiencies in the language and its implementations.

--
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u


James Harris
18.06.2009 - 00:27
On 17 June, 13:36, Charlie Dawson <cd4...@yahoo.com> wrote:

[Sorry about the list of groups - is there anywhere more relevant,
excepting comp.compilers?]

As BartC says you could try comp.lang.misc. It is about more than just
sundry languages but includes language design issues.

James

Nick Keighley
18.06.2009 - 11:02
On 17 June, 13:36, Charlie Dawson <cd4...@yahoo.com> wrote:

<snip>

I've got a fairly simple domain-specific language for engineers (*not*
programmers), which has functions, and which exclusively uses
pass-by-value.

Problem: I've just had to add a complex new stream type. I can't pass
objects of this type to functions by value, because of an
implementation issue; it also wouldn't make much sense, because I
would then be creating multiple objects that shared file state.
However, pass-by-reference is trivial.

The obvious fix is to prohibit pass-by-value in some way. Any thoughts
on the best way to do this? There are two obvious ways to do this, but
I can't make up my mind which is best. Comments welcome.

make your language automatically pass structures by reference.

integer ivan
complex-new-stream-type creek

aardvaak (i) -- pass by value
mesatrope (creek) -- pass by reference

then your engineer types don't have to worry themselves about
this.


#1: a Java-style solution: define the new type to be a reference type.

I was never a fan of reference types and Java always looked borken
in this area to me.

This is nice and simple, and is transparent to the user. However, this
does restrict me if I decide in future that I want to add
pass-by-reference as well as pass-by-value; having a reference type,
*and* pass-by-reference semantics, may just cause confusion to the
user.

just say "no to reference types"

#2: a C++-style solution: add pass-by-reference semantics;

just...



the user is
forced to add an '&' character, or whatever, to a formal to specify
that it's passed by reference.

icky!


This is complex, for a couple of
reasons: there's some busywork in semantic checking, but the real
issue is how I handle structures and arrays containing these new
objects. Having said that, I think it's sufficient to force the user
to add the '&' anywhere an object of the new type can appear:
structure definitions, array declarations, function parameters,
function return values.

The Java solution is simpler, but I can't help feeling that it's not
the right way to do references. It feels like a bodge.

they're both bodges. Think of it from the users' point of view.
They just want to pass a thingy, how it's done is just an
implementation
detail. ie. your problem not theirs.

Take a look at Ada it has in, out and inout (sadly, not shake-it-all-
about)
no references or pointers in sight.



--
Nick Keighley

Most Ada programmers would consider going out of your way to
construct an Ada program that had a potential buffer overflow not as
a challenge, but as a kind of pornography.

torbenm
23.06.2009 - 10:43
Charlie Dawson <cd4573@yahoo.com> writes:


I've got a fairly simple domain-specific language for engineers (*not*
programmers), which has functions, and which exclusively uses
pass-by-value.

Problem: I've just had to add a complex new stream type. I can't pass
objects of this type to functions by value, because of an
implementation issue; it also wouldn't make much sense, because I
would then be creating multiple objects that shared file state.
However, pass-by-reference is trivial.

The obvious fix is to prohibit pass-by-value in some way. Any thoughts
on the best way to do this? There are two obvious ways to do this, but
I can't make up my mind which is best. Comments welcome.

#1: a Java-style solution: define the new type to be a reference type.
This is nice and simple, and is transparent to the user. However, this
does restrict me if I decide in future that I want to add
pass-by-reference as well as pass-by-value; having a reference type,
*and* pass-by-reference semantics, may just cause confusion to the
user.

#2: a C++-style solution: add pass-by-reference semantics; the user is
forced to add an '&' character, or whatever, to a formal to specify
that it's passed by reference. This is complex, for a couple of
reasons: there's some busywork in semantic checking, but the real
issue is how I handle structures and arrays containing these new
objects. Having said that, I think it's sufficient to force the user
to add the '&' anywhere an object of the new type can appear:
structure definitions, array declarations, function parameters,
function return values.

The Java solution is simpler, but I can't help feeling that it's not
the right way to do references. It feels like a bodge.

I agree with the people who advocate option #1. There is no need to add
pass-by-reference to the langage if it has general reference types: You
just pass the reference by value and it works the same way. Lots of
languages do this. Some languages, like Standard ML, go further and say
that reference types are the only mutable objects, so value types are
values that can not be updated destructively.

Another way to prevent creating multiple copies of streams is to make
them linearly typed: A stream value can be used exactly once, and you
get a type error if it is unused or used multiple times. The function
that creates a stream returns such a linearly typed value, reading from
ot writing to the stream returns a new linearly typed stream value (so
it is the only user of the old stream) and, finally, closing the stream
uses the stream value and returns no new stream. This way, you are sure
that all accesses to a stream are threaded and that a stream is closed
before the program ends. If the language is intended for
non-programmers, you should ue type inference rather than require
explicit types, though, so this is a more complicated approach.

Torben




Share/Bookmark

<