const constructors and the "new" keyword

333 views
Skip to first unread message

Chris Buckett

unread,
Apr 29, 2012, 5:57:00 PM4/29/12
to General Dart Discussion
Hi,

I'm wondering why you can use the "new" keyword when using a const
constructor (shown here: http://try.dartlang.org/s/BqY9 )
class Message {
final String msg;
const Message(this.msg);
}

main() {
var msg1 = const Message("msgFirst");
var msg2 = const Message("msgFirst");
print(msg1===msg2); // true

// why can we use the "new"
// keyword with const constructors?
var msgA = new Message("msgSecond");
var msgB = new Message("msgSecond");
print(msgA===msgB); // false
}

If I (as a library designer) define a const constructor, then I would
expect users of my library to always use the const keyword when
instantiating it, but it seems that the editor and dartboard does not
even provide a warning that I'm using "new" with a const constructor.

It works the other way round - I get an error if I use a "const"
keyword when trying to use a non-const constructor, but I get no hint
when I _should_ be using const instead of new.

Cheers,
Chris.

Gilad Bracha

unread,
Apr 29, 2012, 11:25:48 PM4/29/12
to Chris Buckett, General Dart Discussion
Hi Chris,

Allowing new to call const constructors was a deliberate decision. If you wish to obtain an instance, and it happens to be constant, that's ok.  Typechecking can be used to see if the interface you wanted is supported; the fact that no mutation takes place is incidental.  

One thing that bothers some people is the use of the word 'new', since there is no guarantee that a new allocation will take place. This is the case in other situations, such as factory constructors. This is very much intentional because we avoid a classic defect of traditional constructors - one an cache objects, allocate instances of different classes etc.
--
Cheers, Gilad

Chris Buckett

unread,
Apr 30, 2012, 2:59:31 AM4/30/12
to Gilad Bracha, General Dart Discussion
Hi Gilad,

I understand that using "new" with a const constructor may return the same instance (as with factory constructors), it just seems (from the dartboard sample at least) that it doesn't.

In particular, it's the use of "const" when creating objects rather than "new" that bothers me :)

It seems that there is different behaviour depending upon whether I use "new" to create the new object, or "const" to create the new object.  
When I use "const", I get the same instance (given the same parameters), but when using "new", I get a different instance.

Using const to create an object is only supported when the creator of the class has created a const constructor, so perhaps the editor could provide some hinting that this is available, otherwise I could be happily using "new", when the class could actually support "const" (which I guess would be more efficient in terms of object creation).

Cheers,
Chris.

Gilad Bracha

unread,
Apr 30, 2012, 3:09:18 AM4/30/12
to Chris Buckett, General Dart Discussion
Hi Chris,

Sorry if I misunderstood your concern. I think the IDE could provide very gentle feedback - say coloring const constructors differently. A language level warning seems like overkill.
--
Cheers, Gilad

Ladislav Thon

unread,
Apr 30, 2012, 3:29:52 AM4/30/12
to Chris Buckett, General Dart Discussion
If I (as a library designer) define a const constructor, then I would
expect users of my library to always use the const keyword when
instantiating it, but it seems that the editor and dartboard does not
even provide a warning that I'm using "new" with a const constructor.

It works the other way round - I get an error if I use a "const"
keyword when trying to use a non-const constructor, but I get no hint
when I _should_ be using const instead of new.

Here's my understanding of the situation (and I think that Dart does exceptionally well with regards to constructors): "standard" constructors works as usual, always creating a new instance. Factory constructors let you do some "preprocessing", allowing you to for example create a cache or whatever, but it still works at runtime.

Const constructors, on the other hand, are "invoked" at compile time, allowing you to create compile-time constants. I think that nothing in principle forbids creating a new instance of such class at runtime, and sometimes, you want to do so. Having to declare a "standard" constructor in addition to a constant one would be unnecessary duplication. So if you declare a constant constructor -- and you are severely restricted in what can it look like --, you can either invoke it with const (which creates a compile-time constant) or with new (which might create a new object at runtime or not, it doesn't matter). If you declare a standard constructor, you aren't restricted, but you can't create a compile-time constant with it, so you can only invoke it with new.

LT

P.S.: hmm, what about constant factories? No, just kidding :-)

Chris Buckett

unread,
Apr 30, 2012, 4:01:02 AM4/30/12
to General Dart Discussion

> Const constructors, on the other hand, are "invoked" *at compile time*,
> allowing you to create compile-time constants.

It's this bit that gets me - as far as I can tell, this is only true
if you know to use the "const" keyword when invoking them, rather than
using the "new" keyword.

Gilad's suggestion of highlighting constructors that _can_ be called
with const in the editor makes sense.

Cheers,
Chris.

Chris Buckett

unread,
Apr 30, 2012, 4:06:42 AM4/30/12
to General Dart Discussion
That would be good - I'll open a bug request...

Done: http://dartbug.com/2819

Cheers,
Chris.

Ladislav Thon

unread,
Apr 30, 2012, 4:20:24 AM4/30/12
to Chris Buckett, General Dart Discussion
That would be good - I'll open a bug request...

Done: http://dartbug.com/2819

Starred. I like the idea too, even if I don't use the editor.

LT

Christian Grobmeier

unread,
Apr 30, 2012, 4:40:39 AM4/30/12
to Chris Buckett, General Dart Discussion
Starred it, thanks for bringing this up Chris.

Anyway I was always under the impression "new" and "const" would work
the same. When I use "factory" on my constructor I still use "new". It
helps me when I need to refactor my code, because I don't need to
change anything. With "const" constructors it is different, which is
not nice imho. I would have expected that even when I call "new" it is
the same object (given same params) which is returned. Is this
exception really necessary?

cheers,
Christian
--
http://www.grobmeier.de
https://www.timeandbill.de

Florian Loitsch

unread,
May 2, 2012, 2:19:07 PM5/2/12
to Christian Grobmeier, Chris Buckett, General Dart Discussion
On Mon, Apr 30, 2012 at 10:40, Christian Grobmeier <grob...@gmail.com> wrote:
Starred it, thanks for bringing this up Chris.

Anyway I was always under the impression "new" and "const" would work
the same. When I use "factory" on my constructor I still use "new". It
helps me when I need to refactor my code, because I don't need to
change anything. With "const" constructors it is different, which is
not nice imho. I would have expected that even when I call "new" it is
the same object (given same params) which is returned. Is this
exception really necessary?
If I understand correctly you want objects to be canonicalized if they are instantiated through a constructor that is marked as 'const'. Even if they are allocated with 'new'.
Canonicalization can be a relatively expensive procedure (since it is recursive). The runtime overhead could be significant. Especially since often const-constructors exist for small objects that are instantiated a lot of times. It also requires to keep track of all existing objects of this class. For the classical example of "Point" all points would need to be in some hashtable.
In general it is just simpler to override the "==" operator and just make sure that two objects return equal if they would have been canonicalized (if they were allocated with 'const').
// florian

cheers,
Christian

On Mon, Apr 30, 2012 at 10:06 AM, Chris Buckett <chrisb...@gmail.com> wrote:
> That would be good - I'll open a bug request...
>
> Done: http://dartbug.com/2819
>
> Cheers,
> Chris.
>
> On Apr 30, 8:09 am, Gilad Bracha <gbra...@google.com> wrote:
>> Hi Chris,
>>
>> Sorry if I misunderstood your concern. I think the IDE could provide very
>> gentle feedback - say coloring const constructors differently. A language
>> level warning seems like overkill.



--
http://www.grobmeier.de
https://www.timeandbill.de



--
Give a man a fire and he's warm for the whole day,
but set fire to him and he's warm for the rest of his life. - Terry Pratchett

Seth Ladd

unread,
May 2, 2012, 2:33:08 PM5/2/12
to Florian Loitsch, Christian Grobmeier, Chris Buckett, General Dart Discussion
Hi Florian,

Can you help explain why canonicalization costs are different for the following two cases? (I hope I understood your point below...)

class Point {
  final num x, y;
  const Point(this.x, this.y);
}

main() {
  var pNew = new Point(1,2);
  var pConst = const Point(1,2);
}

Thanks in advance,
Seth

Lasse R.H. Nielsen

unread,
May 2, 2012, 3:35:57 PM5/2/12
to Seth Ladd, Florian Loitsch, Christian Grobmeier, Chris Buckett, General Dart Discussion
On Wed, May 2, 2012 at 8:33 PM, Seth Ladd <seth...@google.com> wrote:
> Hi Florian,
>
> Can you help explain why canonicalization costs are different for the
> following two cases? (I hope I understood your point below...)

I'm not Florian, but I'll give it a shot :)

>
> class Point {
>   final num x, y;
>   const Point(this.x, this.y);
> }
>
> main() {
>   var pNew = new Point(1,2);
>   var pConst = const Point(1,2);
> }

Nothing in this simple example prevents the compiler from recognizing
"new Point(1,2)" and creating a constant from in at compile time, if
the language was so designed. You need a more complex example to show
the problem:

main() {
for (int i = 0; i < 4; i++) {
var pNew = new Point(i, i+1);
print(pNew);
}
var pConst = const Point(1,2);
pConst = const Point(2,3);
}

In this case, the arguments to the Point constructor aren't
compile-time constants. That means that to canonicalize the result of
"new Point(i,i+1)", you have to do it at runtime, when you know the
value of "i".
That's where Florian says you need to remember all instances of Point
to be able to dynamically find one, if any, that matches the inputs to
the current constructor call.

As Dart is designed now, there is no such data structures at runtime.
All compile-time constants are created using "const" instead of "new",
and they are created and canonicalized at *compile time*. That's why
"const" constructor calls must only have compile-time constants as
arguments, and why the constructors can't do anything except
initialize fields - it must be done without any code execution.

At runtime, you can only use "new", and it always creates a new object
(for const constructors at least).

So, runtime canonicalization requires a runtime overhead, both in time
whenever you create a new object, and in memory to make it possible to
find an already existing canonical object. The memory overhead is
constantly there, since you never know if your program will create
another object. Dart is designed to not have that overhead.

The compile-time canonicalization has a similar overhead, but it's
static - constrained by the syntax of the program, not the execution,
so each "const" constructor call generates only one constant, not one
every time it's executed - and the data structure can be dropped when
the phase is over, or at least when compilation is over. It only
affects compile-time, not execution time.

Hope this makes sense.
/L
--
Lasse R.H. Nielsen
l...@google.com
'Faith without judgement merely degrades the spirit divine'
Google Denmark ApS - Frederiksborggade 20B, 1 sal - 1360 København K -
Denmark - CVR nr. 28 86 69 84

Seth Ladd

unread,
May 2, 2012, 4:05:31 PM5/2/12
to Lasse R.H. Nielsen, Florian Loitsch, Christian Grobmeier, Chris Buckett, General Dart Discussion
It does, thank you very much. My question is then, would it make sense to make an optimization for "new Point(1,1)" into "const Point(1,1)" (for this particular example, as we have a const constructor) ?  I think this is what Chris is asking (but he'll have to confirm...)

Thanks,
Seth

jerome

unread,
May 2, 2012, 4:50:41 PM5/2/12
to mi...@dartlang.org
Hi

I was wondering the same than Chris Buckett.

For the java programmer I am, object constructed with const constructors were "like state singletons" (not only one instance for the app but one instance by state).

But now, I have more and more questions:

May be the answer to the question is trivial but: what do you mean by  compile-time in dart?

  var date = new Date.now().toString().substring(0,10);
  var msg1 = const Message(date);
  var msg2 = const Message("2012-05-02");
  print(msg1===msg2); // print true in the dart board

What the real aim of const objects, because if my library returns a "Message", there is no warranty for my caller that I use const keyword to construct the object?

Cheers


Srdjan Mitrovic

unread,
May 2, 2012, 4:53:14 PM5/2/12
to Seth Ladd, Lasse R.H. Nielsen, Florian Loitsch, Christian Grobmeier, Chris Buckett, General Dart Discussion
On Wed, May 2, 2012 at 1:05 PM, Seth Ladd <seth...@google.com> wrote:
It does, thank you very much. My question is then, would it make sense to make an optimization for "new Point(1,1)" into "const Point(1,1)" (for this particular example, as we have a const constructor) ?  I think this is what Chris is asking (but he'll have to confirm...)

I think that it would be surprising if "new A() === new A()"  is true/false depending how we define the class.

- Srdjan

Chris Buckett

unread,
May 2, 2012, 5:08:18 PM5/2/12
to General Dart Discussion
Yes, I that's pretty much what I was asking, and the associated
question "how would I know that I can" in the current tools (without
looking at the src to see that a constructor was actually defined as a
constant constructor (which can be dealt with code formatting / code
doc).

Thanks,
Chris.

Ladislav Thon

unread,
May 2, 2012, 5:10:18 PM5/2/12
to jerome, mi...@dartlang.org
For the java programmer I am, object constructed with const constructors were "like state singletons" (not only one instance for the app but one instance by state).

But now, I have more and more questions:

May be the answer to the question is trivial but: what do you mean by  compile-time in dart?

The intuition helps here -- Dart's compile-time is in fact almost the same as Java's compile-time, except that with Dart VM, it happens a little later :-) Dart programs run the same way as Java programs -- they are first compiled and then executed. It blurs a little with Dart VM, because there is no separate compilation step visible to the user, but it's there. Using dart2js, there is an explicit compilation step, which turns Dart source code to (highly optimized, in the future) JavaScript.

Compile-time constants are resolved in this compilation step, so there is no runtime information available. Meaning that you can do var msg2 = const Message("2012-05-02"), if your Message class has a const constructor, because that string literal is also a compile-time constant, but you can't do var msg1 = const Message(new Date.now().toString().substring(0, 10), because new Date.now() is NOT a compile-time constant -- the value is only available at runtime.

  var date = new Date.now().toString().substring(0,10);
  var msg1 = const Message(date);
  var msg2 = const Message("2012-05-02");
  print(msg1===msg2); // print true in the dart board

Dartboard can't be trusted. Really, I'd advise people not to use it at all -- it runs TOOOO old Dart -> JavaScript compiler. Hope it will get updated soon.
 
What the real aim of const objects

I'm not the right person to answer this, but one part of the answer is definitely startup time. Dart aims to start very quickly, which means doing as least initialization as possible. Compile-time constants are one part of solving this problem.
 
Hope that helps (a little).

LT 

Chris Buckett

unread,
May 2, 2012, 5:10:34 PM5/2/12
to General Dart Discussion
> I think that it would be surprising if "new A() === new A()"  is true/false
> depending how we define the class.

Bear in mind that we already have that situation with factory
constructors. IMHO it's up to the library designer to use factory
constructors in a very sensible way so that a user of the class
wouldn't be surprised even though new A() === new A().

Cheers,
Chris.

jerome

unread,
May 2, 2012, 5:25:23 PM5/2/12
to mi...@dartlang.org, jerome

Thank you ladicek.
That's help a lot (ok for the compile time). 
It's clear for me now.

Effectively, I have an error in the dart editor (expression must be a compile time constant : var msg1 = const Message(date);)

Jerome
Reply all
Reply to author
Forward
0 new messages