David R. MacIver's Blog
Dereferencing operators
I’m writing a small library for mutable reference cells. This has spawned a heated debate about what to call the dereferencing operator. Possible options for dereferencing foo are:
One of the big questions is whether it should be postfix or prefix. If it’s postfix, using them as properties becomes much more readable. foo.bar! vs. !(foo.bar). But it also runs into weird precedence issues. On the other hand, the set of characters which can be used in a prefixy manner is really limited and they all seem to have significant meaning.
!foo
Pros: Historical precedent. It’s what ML uses.
Cons: Very easy to confuse with negation. Suppose foo is a reference to
a boolean. if (!foo) { } is potentially really confusing.
foo!
Pros: Same as !foo. Less confusing - it’s not currently used by
anything major.
Cons: Retains misleading association with negation, although less easy
to write confusing code.
foo&
Pros: Historical precedent. Looks almost like C (prefix & isn’t
legal).
Cons: Similar confusion to !. & more normally means and. On the
other hand, C programmers seem to have gotten used to it.
@foo
Pros: Nice distinctive character. Easy to get used to.
Cons: It isn’t legal Scala (this is kinda a big one :-) ).
~foo
Pros: Same as @. Legal Scala. :-)
Cons: Prefix operator, so doesn’t work well with properties. Somewhat
non-obvious.
foo<> (credit to Bob Jones... err. I mean Jan Kriesten for this
one)
Pros: Visually distinctive and appealing.
Cons: Looks vaguely directional.
foo^ (credit to Martin Odersky)
Pros: Um. Beats me.
Cons: Confusion with xor. Looks weird.
foo deref
Pros: Fewer weird precedence issues because it’s not an operator.
Some people seem to like wordy operator names.
Cons: Visually distracting, overly verbose. Scatters meaningless words
throughout the code. Core operations should have nice symbolic
notation.
Additional cons: Over my dead body.
foo() (credit to Eric Willigers)
Pros: Interacts much better with precedence rules than any of the
others. You can write foo() == “Bar” whereas you’d have to write (foo!)
== “Bar”. It seems intuitively obvious what invoking a reference should
mean.
Cons: I don’t really have a good argument against this except that it
feels wrong. It looks a little weird when you have a reference to a
function. e.g. if you had a Ref[() => Unit] it would be potentially
easy to write myRef() and think you’d invoked it, when in fact you’d
merely returned a function.
Any of the above with an implicit conversion from references to their
contents
Pros: The mainline case is syntax free.
Cons: No no no no no no no. This creates *exactly* the sort of confusion
between reference cells and their values that I’m trying to avoid, and
opens up the possibility of huge classes of subtle bugs where you passed
a reference to an object and meant to pass the object. I initially
thought it was a good idea, and it has a strong intuitive appeal to it,
but I’m convinced it would be disastrous. A slight conciseness advantage
in no way offsets the introduction of perniciously evil bugs.
On balance I think foo() is going to win. The precedence issues seem to prohibit the use of any sort of postfix operator. This seems to leave ~foo as the only good alternative, and I think it’s less obviously meaningful and the prefix nature would annoy the properties people.
Comments
Mike on 2008-01-06 16:37:00:
I suspect the foo^ suggestion was a nod to Pascal.
I’ve always been a fan of how assemblers do it. Of course every
assembler does it differently, but usually the syntax is (foo) or [foo].
(foo) would probably never work in a mainstream language, because
parentheses are used to mark parenthetical expressions. [foo] might be
workable :)
I have to say, though, foo() is a good idea and one I’ve never thought
of.
David R. MacIver on 2008-01-06 16:51:00:
Ah, that’s probably it. I don’t know Pascal - the only syntax
families I’ve used have been variants on C, ML and Lisp.
[foo] is interesting. Not legal Scala, but definitely interesting.
I agree. foo() is a good idea and wouldn’t have occurred to me if Eric
hadn’t suggested it. But it feels wrong somehow. Still, I think it’s the
direction the language is forcing me in.
andy_f on 2008-01-06 22:39:00:
The association with Perl makes me wince, but how about ->
David R. MacIver on 2008-01-06 22:41:00:
The problem I had with -> which caused me to dismiss it is that it looks very directional. So if I see x -> I wonder what x is pointing to. :-)
Pseudonym on 2008-01-07 02:04:00:
BLISS used a dot, which is interesting. Mind you, it didn’t have
modules.
X = .Y
Kevin on 2008-01-07 02:45:00:
In E, we
currently use foo[], which is just the subscript operator with no
arguments. That is, a slot (cell, mutable or not) is essentially a
zero-dimensional collection.
(foo[bar...] is syntactic sugar for foo.get(bar...).)
helium on 2008-01-25 15:35:00:
In C and C++ you use * to dereference.