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.

This entry was posted in programming and tagged , on by .

7 thoughts on “Dereferencing operators

  1. Mike

    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.

  2. David R. MacIver

    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.

  3. David R. MacIver

    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. :-)

  4. Kevin

    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…).)

Comments are closed.