static final vs final static

2,382 views
Skip to first unread message

Ali Ok

unread,
Oct 20, 2011, 5:51:37 PM10/20/11
to General Dart Discussion
Hi,

Do you think a final static field _must_ be declared like
"static final MyClass SOME_RUNTIME_CONSTANT = ...;"
and not
"final static MyClass SOME_RUNTIME_CONSTANT = ...;"
?

It is like that in spec.

My main language is Java and in there, both ways are supported. I've
always used the second one.
When I think about it, first one makes more sense. IMHO being static
is more important than being final when you first read the code (I am
gonna use first way in Java now on :) ).

So, is this case overlooked, or is it a best practice thus it is in
the spec?

It took me some some time to figure out what was wrong in my code with
compiler message :)

BlockType.dart/BlockType.dart:6: Unexpected token
'IDENTIFIER' (expected ';')

final static BlockType THREES = new BlockType.withSize(3);

Greetings,
Ali

Bob Nystrom

unread,
Oct 20, 2011, 6:04:41 PM10/20/11
to Ali Ok, General Dart Discussion
On Thu, Oct 20, 2011 at 2:51 PM, Ali Ok <al...@aliok.com.tr> wrote:
Hi,

Do you think a final static field _must_ be declared like
"static final MyClass SOME_RUNTIME_CONSTANT = ...;"
and not
"final static MyClass SOME_RUNTIME_CONSTANT = ...;"
?

It is like that in spec.

Right.
 

My main language is Java and in there, both ways are supported. I've
always used the second one.

It's a little different in Java. In Java, every variable has to have a type declaration. In Dart, you can do:

int foo; // just the type
var foo; // var instead of type
final foo; // final instead of type
final int foo; // final + type

So "final" is (sort of) part of the type declaration in Dart. From that angle, it makes sense that you can't jam a "static" in the middle of it.
 
When I think about it, first one makes more sense. IMHO being static
is more important than being final when you first read the code (I am
gonna use first way in Java now on :) ).

That's my intuition too.
 

So, is this case overlooked, or is it a best practice thus it is in
the spec?

It's in the spec, I think.
 

It took me some some time to figure out what was wrong in my code with
compiler message :)

BlockType.dart/BlockType.dart:6: Unexpected token
'IDENTIFIER' (expected ';')

Yeah, we could definitely have a more helpful error here. :(


final static BlockType THREES = new BlockType.withSize(3);

For what it's worth, our convention is to omit the explicit type annotation for final variables:
 
static final THREES = new BlockType.withSize(3);

Our reasoning is that since it requires an initializer and the variable can't change, the type is obvious from the declaration.

- bob

Dirk Detering

unread,
Oct 20, 2011, 11:40:02 PM10/20/11
to Bob Nystrom, Ali Ok, General Dart Discussion


Am 21.10.2011 00:05 schrieb "Bob Nystrom" :
> It's a little different in Java. In Java, every variable has to have a type declaration. In Dart, you can do:
>
> int foo; // just the type
> var foo; // var instead of type
> final foo; // final instead of type
> final int foo; // final + type
>
> So "final" is (sort of) part of the type declaration in Dart. From that angle, it makes sense that you can't jam a "static" in the middle of it.
>

Hmmm. Put static into account and you have:

static int foo // static + type

So I assume  static foo  is not possible, but must be static var foo?


 
> For what it's worth, our convention is to omit the explicit type annotation for final variables:
>  
> static final THREES = new BlockType.withSize(3);
>
> Our reasoning is that since it requires an initializer and the variable can't change, the type is obvious from the declaration.

FWIW, I find it annoying that Dart has the javaish static final again. Even in java land has been discussed to find a single keyword to express the donated semantic instead of the more technical notion of a 'static' and 'final' "variable" (psaw!)

When I read that Dart has the keyword 'const' I hoped that this would be exactly this...

So please get rid of those 'static final' noise.

It is :

  const  PI = 3.14;

KR
Det

Zexx

unread,
Oct 21, 2011, 5:11:30 AM10/21/11
to General Dart Discussion
> So please get rid of those 'static final' noise.
>
> It is :
>
>   const  PI = 3.14;
>
> KR
> Det


I agree. "static final" is a bit long, hard to read and looks archaic.
"const" is simple and elegant.

Adam Gray

unread,
Oct 21, 2011, 10:13:10 AM10/21/11
to General Dart Discussion
If I understand it correctly you can have static final, just static, or just final.  Combining those doesn't make sense at all.  const and final could be considered the same, but static is something different entirely.

Dirk Detering

unread,
Oct 21, 2011, 11:57:12 AM10/21/11
to Adam Gray, General Dart Discussion

This is debatable and may be true much more in Java.
But IIRC in Dart statics can only be initialized with literals, so I assume the main purpose will be to declare constant values.

So a final variable pointing to a mutable object ist not const in the sense of constant.  An immutable value (literal) assigned to a final variable which is after all even static, is semantically much more a constant than anything else.

KR
Det

Bob Nystrom

unread,
Oct 21, 2011, 1:30:34 PM10/21/11
to Dirk Detering, Adam Gray, General Dart Discussion
On Fri, Oct 21, 2011 at 8:57 AM, Dirk Detering <mail...@googlemail.com> wrote:

So a final variable pointing to a mutable object ist not const in the sense of constant.

Exactly right. "static", "final", and "const" mean entirely distinct things in Dart:

"static" means a member is available on the class itself instead of on instances of the class. That's all it means, and it isn't used for anything else. "static" modifies members.

"final" means single-assignment: a final variable or field must have an initializer, and it that initializer is the only time it can be assigned to. "final" modifies variables.

"const" means has a meaning that's a bit more complex and subtle in Dart. "const" modifies values. You can use it when creating collections, like const [1, 2, 3], and when constructing objects (instead of new) like const Point(2, 3). Here, "const" means that the object's entire deep state can be determined entirely at "compile time" and that the object will be frozen and completely immutable.

Const objects have a couple of interesting properties and restrictions:
1. They must be created from data that can be calculate at compile time: no access to anything you would need to calculate at runtime. 1 + 2 is a valid const expression, but new DateTime.now() is not.
2. They are deeply, transitively immutable. If you have a final field containing a collection, that collection can still be mutable. If you have a const collection, everything in it must also be const, recursively.
3. They are canonicalized. This is sort of like string interning: for any given const value, a single const object will be created and re-used no matter how many times the const expression(s) are evaluated. In other words:

getConst() => const [1, 2];

main() {
  var a = getConst();
  var b = getConst();
  print(a === b); // true
}


I think Dart does a pretty good job of keeping the semantics and the keywords nicely clear and distinct. (There was a time where const was used both for const and final. It was confusing.) The only downside is that when you want to indicate a member that is single-assignment and on the class itself, you have to use both keywords: static final.

- bob

John Tamplin

unread,
Oct 21, 2011, 1:42:49 PM10/21/11
to Bob Nystrom, Dirk Detering, Adam Gray, General Dart Discussion
On Fri, Oct 21, 2011 at 10:30 AM, Bob Nystrom <rnys...@google.com> wrote:
Const objects have a couple of interesting properties and restrictions:
1. They must be created from data that can be calculate at compile time: no access to anything you would need to calculate at runtime. 1 + 2 is a valid const expression, but new DateTime.now() is not.
2. They are deeply, transitively immutable. If you have a final field containing a collection, that collection can still be mutable. If you have a const collection, everything in it must also be const, recursively.
3. They are canonicalized. This is sort of like string interning: for any given const value, a single const object will be created and re-used no matter how many times the const expression(s) are evaluated. In other words:

4. They can be shared between isolates (an implementation detail related to #2, but is an important reason why they exist).

--
John A. Tamplin
Software Engineer (GWT), Google

Bob Nystrom

unread,
Oct 21, 2011, 1:50:25 PM10/21/11
to John Tamplin, Dirk Detering, Adam Gray, General Dart Discussion
Ah, yes! My favorite feature of immutability and I forgot to mention it. :)

- bob
 

Dirk Detering

unread,
Oct 21, 2011, 2:30:26 PM10/21/11
to Bob Nystrom, General Dart Discussion, Adam Gray

Thanks for the declaration, Bob.

Just some thoughts:

-  If you often combine distinct concepts to express a specific semantic notion, it is of much value to give it a specific name and so go to the next level of abstraction.
For me 'static final' is such a combination: the semantic is: named value. (See PI)

- Using OTOH the const keyword on the right side of an assignment is not to typical, at least for me.
The semantic is:  immutable data,   i.e.  value object.

I all data structure would be deeply immutable, like debated somwhere else, you wouldn't need a const keyword on the value side, but it would be even right on the named-ref side:

   Const somename = Point(3,4);   //  immutable anyway.

So it feels like const is reserved for the wrong part of the expression.

John Tamplin

unread,
Oct 21, 2011, 2:44:51 PM10/21/11
to Dirk Detering, Bob Nystrom, General Dart Discussion, Adam Gray
On Fri, Oct 21, 2011 at 11:30 AM, Dirk Detering <mail...@googlemail.com> wrote:

I all data structure would be deeply immutable, like debated somwhere else, you wouldn't need a const keyword on the value side, but it would be even right on the named-ref side:

If everything is deeply immutable, then you are talking about a very different language and might as well just use some existing functional language.  Dart is not aiming at people who want a functional language, but rather more from the mainstream of C/C++/C#/Java/JS programmers.

Bob Nystrom

unread,
Oct 21, 2011, 5:04:55 PM10/21/11
to Dirk Detering, General Dart Discussion, Adam Gray
On Fri, Oct 21, 2011 at 11:30 AM, Dirk Detering <mail...@googlemail.com> wrote:

Thanks for the declaration, Bob.

Just some thoughts:

-  If you often combine distinct concepts to express a specific semantic notion, it is of much value to give it a specific name and so go to the next level of abstraction.
For me 'static final' is such a combination: the semantic is: named value. (See PI)

I agree with your perspective but I don't think static final really does make that distinction. You can have static finals that are mutable (and we do, in practice) so it's not like they're really just constant named values.

My hunch is that we're worrying about this more than we need to. There are a decent amount of static finals in current Dart code, but I think that's a holdover from its early history from before we had top-level definitions. Now that we do, I'd like most of those static finals to just be top level variables. Why do:

class Math {
  static final PI = 3.1415926535;
}

And then do Math.PI everywhere, when you can just do:

final PI = 3.1415926535;

and then just use PI.

Not that I'm saying PI will be moved to the top level, but I'd personally like a lot of our statics to become top level variables.

- Using OTOH the const keyword on the right side of an assignment is not to typical, at least for me.
The semantic is:  immutable data,   i.e.  value object.

It's not that const is on the RHS of an assignment, it's that it's an expression. You can also do:

someFunction(const Point(3, 4));

or

const Point(1, 2) + const Point(3, 4);

I all data structure would be deeply immutable, like debated somwhere else, you wouldn't need a const keyword on the value side, but it would be even right on the named-ref side:

   Const somename = Point(3,4);   //  immutable anyway.

So it feels like const is reserved for the wrong part of the expression.

The semi-functional programmer in my is sympathetic here, but I actually find mutability to be pretty handy. Especially when you don't have shared state concurrency anyway, I don't think mutability is that hard to reason about, and it's a good fit for things like UI and games.

It's also, like it or not, the mental model already internalized by lots of programmers. Learning to think in terms of immutability is a high tax to ask our new users to pay.

- bob

John Tamplin

unread,
Oct 21, 2011, 5:50:38 PM10/21/11
to Bob Nystrom, Dirk Detering, General Dart Discussion, Adam Gray
On Fri, Oct 21, 2011 at 2:04 PM, Bob Nystrom <rnys...@google.com> wrote:
My hunch is that we're worrying about this more than we need to. There are a decent amount of static finals in current Dart code, but I think that's a holdover from its early history from before we had top-level definitions. Now that we do, I'd like most of those static finals to just be top level variables. Why do:

class Math {
  static final PI = 3.1415926535;
}

And then do Math.PI everywhere, when you can just do:

final PI = 3.1415926535;

and then just use PI.

Not that I'm saying PI will be moved to the top level, but I'd personally like a lot of our statics to become top level variables.

The problem is there is only one top level, and if everything useful goes there so you don't have to disambiguate it, you will wind up having to disambiguate it with a library prefix to avoid collisions and then you have to prefix everything in that library, not just the constants.

It is definitely a tradeoff, but I suspect if this approach were heavily used we would need to add a finer-granularity way of prefixing imports.

Bob Nystrom

unread,
Oct 21, 2011, 6:11:51 PM10/21/11
to John Tamplin, Dirk Detering, General Dart Discussion, Adam Gray
On Fri, Oct 21, 2011 at 2:50 PM, John Tamplin <j...@google.com> wrote:
On Fri, Oct 21, 2011 at 2:04 PM, Bob Nystrom <rnys...@google.com> wrote:
My hunch is that we're worrying about this more than we need to. There are a decent amount of static finals in current Dart code, but I think that's a holdover from its early history from before we had top-level definitions. Now that we do, I'd like most of those static finals to just be top level variables. Why do:

class Math {
  static final PI = 3.1415926535;
}

And then do Math.PI everywhere, when you can just do:

final PI = 3.1415926535;

and then just use PI.

Not that I'm saying PI will be moved to the top level, but I'd personally like a lot of our statics to become top level variables.

The problem is there is only one top level, and if everything useful goes there so you don't have to disambiguate it, you will wind up having to disambiguate it with a library prefix to avoid collisions and then you have to prefix everything in that library, not just the constants.

This is a longer discussion that we'll probably have gradually as we build up more libraries, but I agree without in general but still think that's an improvement.

In either case you may need to disambiguate. The nice thing about using library prefixes is that that disambiguation only needs to happen in the actual places where there are collisions. If you stuff something as a static in a class every user everywhere has to type that class name every time. If you use a library prefix, users where there is no collision at least have the option to not use the prefix.

It's also been my experience that collisions are much rarer than people think. We won't know for certain until we build up some libraries, but my strong hunch is that most names won't collide, even if we use top-level definitions pretty freely.


It is definitely a tradeoff, but I suspect if this approach were heavily used we would need to add a finer-granularity way of prefixing imports.

True, we may want that. But I'd personally like to push in that direction and fix imports if we need to. I want nice readable, contextual, terse code. I don't want to have to read UselessUtilsClassName.niceFunction(...) everywhere when I can just do niceFunction(...).

- bob

Bob Nystrom

unread,
Oct 21, 2011, 6:20:13 PM10/21/11
to Dirk Detering, General Dart Discussion, Adam Gray
On Fri, Oct 21, 2011 at 2:04 PM, Bob Nystrom <rnys...@google.com> wrote:

I agree with your perspective but I don't think static final really does make that distinction. You can have static finals that are mutable (and we do, in practice) so it's not like they're really just constant named values.

As someone pointed out to me, I'm totally wrong here. Oopsie! I got static non-finals (which can be mutable) and non-static finals (which also can be mutable) mixed into one lump in my mind. In a class, static final members are indeed always const.

I still think it's the most clear (even if not the most terse) to use "static final" when declaring them because you can understand them completely in terms of those two words and their existing semantics, but you're right they are pretty much always "named values".

I think the other point still holds: I'd generally like to reduce the number of static finals we have and try to use top-level finals more, but we'll have to see how that goes. :) 

- bob

Reply all
Reply to author
Forward
0 new messages