#127 Const feature

brian Wed 27 Dec 2006

I've fully implemented the const feature. The const keyword is applied to a field to make it immutable - similar to the semantics of final in Java. The const keyword is applied to a class to enforce that all of it's fields are const, which effectively makes it immutable and safe to pass between threads. The full list of rules related to const fields:

  • Static fields must be const since they are effectively global variables visible to all threads (use Thread.locals as an alternative)
  • Static const fields can only be set inside a static initializer
  • Instance const fields can only be set inside a constructor
  • Const fields cannot have a getter or setter
  • Const fields can never be set via reflection
  • Const fields must be a const type or be a List/Map of const types
  • Setting a const List/Map must call the toConst() method before assignment
  • List.toConst/Map.toConst are basically a "deep ro()" to ensure something like Str[][] is truly immutable

Rules for const classes:

  • A const class cannot contain any non-const fields
  • A const class cannot inherit from a non-const class
  • A non-const class cannot inherit from a const class
  • A mixin cannot be declared const
  • An enum is implied to be const

Note that const in Fan works a bit different than final in Java. Final in Java means the field can be set exactly once, but in Fan const only restricts where it is set (ctor or static initializer), not how many times it is set (personally I find the Java rules annoying when trying to use final for immutability).

CashMonkey Sun 11 Oct 2009

Just been read through the post and looking at the language. It looks really exciting and seems to have cleaned by a lot of the repeated mistakes in other languages.

Do you really want to compare your semantics to Java's final keyword? Java's final is hardly useful as you have already said. What about C++'s const? It's the only good thing left in C++. You can mark object "queries" and enforce them, and mark objects as immutable and the interface is already defined for you as you have marked your queries.

Any plans on enforcible object queries like with a C++ const keyword? Java left it out and now it's too late for them add it http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4211070.

brian Sun 11 Oct 2009

Hi CashMonkey,

This post is from 2006, so its kind of a blast from the past! But not too much has changed since then.

Const effectively isn't really like Java's final. Const means immutable, and immutability is strongly wired up into Fan's type system. I am not sure supporting const in method parameters makes sense. There are occasions when it comes up, in which case you can do this:

Void foo(Obj mustBeImmutable)
{
  if (!mustBeImmutable.isImmutable) throw NotImmutableErr()
}

But in practice, that hardly ever comes up enough. More likely what happens is the method signature if for a const class already. Or you assign the reference to a const field and get compiler/runtime error.

casperbang Sun 11 Oct 2009

It's the only good thing left in C++ and it is so useful.

Just thinking loud here: Does this comparison even make sense? In C++ one can simply cast Const away when it's inconvenient so it doesn't REALLY say anything about immutability does it?

CashMonkey Mon 12 Oct 2009

Thanks for the reply Brian.

The part of the const keyword that I think should be continued is marking queries of an obj. It could also be used to mark preconditions too but your alternative looks fine. What I mean by a query is a method that does not change the state of the obj http://martinfowler.com/bliki/CommandQuerySeparation.html. Does the compiler determine queries by itself http://fandev.org/doc/sys/Func.html? If that's the case then the only advantage of a query marker would be compiler enforcement and a contract in the obj of a query method.

An example:

class Foo

Int bar
Int baz

query1() const
  return sum(bar, baz)

query2() const
  return sum(bar, baz, 6)

command()
  bar=bar*3

class ImmutibleFoo

query1() const
query2() const

brian Mon 12 Oct 2009

OK - I understand what you are proposing now.

I am not sure that would make much sense in Fan, because const is captured in the type system by the class hierarchy. I am not sure quite how to explain it, but something that I just feel I would never do after writing tons of Fan code.

And to answer your question, yes the compiler handles immutability of Funcs by checking if they capture mutable state from their lexical scope.

Now what I would like (and maybe you are getting at this) is the ability to mark a method as "pure", where pure means absolutely no side-effects. I think maybe D might have this feature. I have use cases for that now, but I wouldn't consider adding to the language for 1.0 until we get existing feature set rock solid.

But the whole immutability area is still an area ripe for future work.

CashMonkey Mon 12 Oct 2009

That is exactly what I was proposing. Since the compiler handles obj queries automatically the only advantage of marking a method as pure I can see would be, as I said above, compiler enforcement and a contract in the obj of a query method.

I'm sure you already know what would feel the most consistent in Fan but I would like to point out that in C++ no side-effect methods are marked with the const keyword, as in my example above, as well as immutable variables.

const std::string& getName() const

One thing to note is that in C++ the const keyword can feel viral. You make one method const then all the methods in that method need to be const. It's a trade-off but such immutability and no side effect enforcement does at the very least help to isolate bugs.

casperbang Tue 13 Oct 2009

One thing to note is that in C++ the const keyword can feel viral.

Yes, that's the shadow world Anders Hejlsberg is talking about. However, I've heard rumors that C# 5.0 is tackling side effect through code contracts (as well as STM). Hopefully we will get some sort of preview at this years PDC.

CashMonkey Tue 13 Oct 2009

I see your point Casper. Strictly enforcing a “no side effects” modifier would be really hard. What if a method calls an external library that does not mark side effects? How will the compiler know if it’s a no side effects method? In C++, you just cast the const away and the modifier still feels useful as you know that you need to justify any const removals. Then everyone thinks, what was the point of having it in the first place if you can cast it away? Seems there are some problems to solve if you are to have a method const modifier.

helium Tue 13 Oct 2009

In C++ const guarantees absolutely nothing. A const pointer or reference can point/refer to a mutable object. A const object can contain data which is marked as mutable. const can be casted away. C++'s const doesn't provide any useful information. D tries to fix the const concept but gets a little complex IMO.

Tracking pureness of functions on the other hand makes a lot of sense. The only problem is the FFI where you would have to manually mark which methods are pure and which aren't.

qualidafial Tue 13 Oct 2009

const can be casted away.

Well, Fan has sys::Unsafe. So there. :)

On some level I would be in favor of introducing some reserved word to mark function args as unmodifiable. However const has a very different meaning than "you're not allowed to mutate this object", and I think it would be confusing to have const used for both concepts.

Login or Signup to reply.