Unexpected behaviour assigning num to int.

640 views
Skip to first unread message

Rhys van der Waerden

unread,
May 19, 2012, 11:56:10 PM5/19/12
to General Dart Discussion
Using num, one can assign a double to an integer without error or
warning as in the following code:

http://try.dartlang.org/s/ZtJA

I would have expected assignment to floor and cast to int. Is this
intentional?

(Sorry if this has been discussed before, I did a quick search and
didn't find anything)

Ross Smith

unread,
May 20, 2012, 12:05:41 AM5/20/12
to General Dart Discussion
note that this will throw in the VM in checked mode:

Unhandled exception:
type 'Double' is not a subtype of type 'int' of 'x'.

Ladislav Thon

unread,
May 20, 2012, 2:55:03 AM5/20/12
to Rhys van der Waerden, General Dart Discussion
Using num, one can assign a double to an integer without error or
warning as in the following code:

http://try.dartlang.org/s/ZtJA

Actually, you can assign anything to an int, because Dart is dynamically typed. So you can do

int x = "abc";

You are probably getting confused by Dart's optional typing, like so many people before (and after). I'd recommend you to read http://www.dartlang.org/articles/optional-types/ and probably also http://www.dartlang.org/articles/why-dart-types/, that should help. But basically, it all revolves around one simple rule: type annotations don't affect behavior. So yes, this

I would have expected assignment to floor and cast to int. Is this
intentional?

is intentional.

LT

Bob Nystrom

unread,
May 21, 2012, 12:19:52 PM5/21/12
to Ladislav Thon, Rhys van der Waerden, General Dart Discussion
As ever, Ladislav is on the money here. Some additional detail to walk through the language semantics in question:

  num n = 3.56;

Here, we assign a floating point literal whose static type is double to a variable annotated to be type num. num is a supertype of double so you're doing an upcast here. Like most languages an upcast is always safe and OK. No warnings here.

  int x = n;

Here, the static type of n is num and we are assigning it to a variable whose annotated type is int. int is a subtype of num, so in this case we are doing a downcast. In most statically typed languages, you would need an explicit cast operator, like:

  int x = (int)n;

Dart is different here. It has something called "assignment compatibility" to determine which assignments are valid. Most languages just use the normal subtyping rules for this: an assignment is safe if you assign from a sub- to a supertype. Dart's assignment compatibility rules also allow assigning from a super- to a subtype.

In other words, you can downcast implicitly in an assignment, without needing any kind of explicit cast. So there's no static warning here. However, if you run the code in checked mode and that downcast turns out to be invalid (as it is here), you will get a type error at runtime when you try to assign a double to x.

By analogy to Java, your code is similar to:

Object n = 3.56;
Integer x = (Integer)n;

A Java compiler will allow this, but it will fail at runtime. The main difference from Dart is that in Java you need that explicit (Integer) cast to downcast.

- bob

Rhys van der Waerden

unread,
May 21, 2012, 12:28:07 PM5/21/12
to Bob Nystrom, Ladislav Thon, General Dart Discussion
Excellent explanation, thank you for clarifying.

Rhys

Tom

unread,
May 25, 2012, 2:19:46 AM5/25/12
to General Dart Discussion
Can we cast to any type, not just downcast? For example, we might have
an object implement two irrelevant interfaces, can we cast between
them? For example,

I1 a = xxx;
I2 b = a; //compiler warning since I2 is not a subtype or supertype of
I1

On May 22, 12:19 am, Bob Nystrom <rnyst...@google.com> wrote:
> As ever, Ladislav is on the money here. Some additional detail to walk
> through the language semantics in question:
>
>   num n = 3.56;
>
> Here, we assign a floating point literal whose static type is double to a
> variable annotated to be type num. num is a supertype of double so you're
> doing an upcast here. Like most languages an upcast is always safe and OK.
> No warnings here.
>
>   int x = n;
>
> Here, the static type of n is num and we are assigning it to a variable
> whose annotated type is int. int is a *sub*type of num, so in this case we
> are doing a downcast. In most statically typed languages, you would need an
> explicit cast operator, like:
>
>   int x = (int)n;
>
> Dart is different here. It has something called "assignment compatibility"
> to determine which assignments are valid. Most languages just use the
> normal subtyping rules for this: an assignment is safe if you assign from a
> sub- to a supertype. Dart's assignment compatibility rules also allow
> assigning from a super- to a subtype.
>
> In other words, you can *downcast* implicitly in an assignment, without
> needing any kind of explicit cast. So there's no *static* warning here.
> However, if you run the code in checked mode and that downcast turns out to
> be invalid (as it is here), you *will* get a type error at runtime when you
> try to assign a double to x.
>
> By analogy to Java, your code is similar to:
>
> Object n = 3.56;
> Integer x = (Integer)n;
>
> A Java compiler will allow this, but it will fail at runtime. The main
> difference from Dart is that in Java you need that explicit (Integer) cast
> to downcast.
>
> - bob
>
>
>
>
>
>
>
> On Sat, May 19, 2012 at 11:55 PM, Ladislav Thon <ladi...@gmail.com> wrote:
> > Using num, one can assign a double to an integer without error or
> >> warning as in the following code:
>
> >>http://try.dartlang.org/s/ZtJA
>
> > Actually, you can assign *anything* to an int, because Dart is *
> > dynamically* typed. So you can do
>
> > int x = "abc";
>
> > You are probably getting confused by Dart's optional typing, like so many
> > people before (and after). I'd recommend you to read
> >http://www.dartlang.org/articles/optional-types/and probably also
> > basically, it all revolves around one simple rule: *type annotations
> > don't affect behavior*. So yes, this

Ladislav Thon

unread,
May 25, 2012, 4:36:21 AM5/25/12
to Tom, General Dart Discussion
Can we cast to any type, not just downcast? For example, we might have
an object implement two irrelevant interfaces, can we cast between
them? For example,

I1 a = xxx;
I2 b = a; //compiler warning since I2 is not a subtype or supertype of
I1

AFAIK, you can assign Dynamic to everything, so

I2 b = a.dynamic;

should let the warning disappear.

Just to explain more: if you imagine a tree of inheritance, then according to Dart's type system, it's intentionally correct to assign any type to any other if and only if they are on the same path from the root of the tree. In this case, the tree would look something like

Object
|   |
I1  I2
|   |
Fubar (implements I1, I2)

(Maybe I shouldn't draw I1 and I2 under Object and as separate roots instead, but I think it will do for now.)

If you had an interface I3 extends I1, then the Dart's type system wouldn't complain on I3 b = a; because

Object
|   |
I1  I2
|   |
I3  |
|   |
Fubar (implements I1, I2)


And then, there is the type Dynamic, which can be assigned to anything. And there is a getter called dynamic in the Object class, so every object has it.

Hope that helps.

LT

Bob Nystrom

unread,
May 25, 2012, 1:08:07 PM5/25/12
to Ladislav Thon, Tom, General Dart Discussion
Ladislav is exactly right here. Dart lets you upcast and downcast without any static warnings. It doesn't let you "sidecast" between two types where one isn't the supertype of the other.

However, because both Object and Dynamic are supertypes of everything (more or less, Gilad will probably school me on some details here), you can always get from any two types by doing an intermediate cast to one of those:

// Two unrelated types:
class Foo {}
class Bar {}

Foo foo = new Foo();
Bar bar = foo; // Static warning.

Object obj = foo; // OK: upcast.
Bar bar2 = obj; // OK: downcast.

var dyn = foo; // OK: upcast to Dynamic.
Bar bar3 = dyn; // OK: downcast.

If you visualize your type hierarchy like a tree, then Dart lets you go up and down branches. If you want to hop across from one branch to another, though, you have to first walk up to an ancestor both branches share.

- bob

Will Squire

unread,
Jun 28, 2015, 5:46:00 PM6/28/15
to mi...@dartlang.org, tom....@gmail.com, lad...@gmail.com
Hi, I've just posted a question on stack and was kindly pointed here, the question being: http://stackoverflow.com/questions/31104110/no-type-error-when-passing-a-super-class-object-via-a-sub-class-argument-in-dart

I just wanted to know if there is anything in store for Dart's IDE to try and detect errors that this pattern can cause.

The way I see it this "feature" can trade flagging potential errors in the IDE for potential errors at runtime? So by offloading this as something that is validated as part of the language, I take the IDE is now going to try and do type inference in future iterations, smartening up to try and make this safer? 

Since Dart is optionally typed, and I can't explicitly set a type in this instance (as Object is the main super class):

class ClassTest {
 
int i;
}


void a(Object x) {
  b
(x); // ClassTest inherits Object, but that doesn't mean it has the same interface
}


void b(ClassTest x){
  x
.i = 2; // a() can pass a non type safe class to make this fail
}

I'd love to have the option to see potential type errors flagged without me having write if (x is ClassTest) or carry out reflection. 

Does anyone know if this is in the future for Dart?

Thanks.

Bob Nystrom

unread,
Jun 29, 2015, 11:46:10 AM6/29/15
to General Dart Discussion, Tom Yeh, Ladislav Thon
On Sun, Jun 28, 2015 at 2:46 PM, Will Squire <will.mj...@googlemail.com> wrote:
I'd love to have the option to see potential type errors flagged without me having write if (x is ClassTest) or carry out reflection. 

Personally, I would too. I think implicit downcasting is useful 1% of the time and masks bugs the other 99% of the time.
 
Does anyone know if this is in the future for Dart?

I don't know of any plans to change how this works, but maybe some other people on the team are poking at things I'm not aware of.

I could maybe imagine a way to infer when an implicit downcast should be allowed and when it shouldn't, but my guess is that that kind of inference might fall down in a lot of places.

Cheers!

- bob

Will Squire

unread,
Jun 29, 2015, 2:58:59 PM6/29/15
to mi...@dartlang.org, tom....@gmail.com, lad...@gmail.com
Yes that's exactly what I'd love to see :) . Explicit indication of where this feature can be used would be great because it would help prevent errors it can cause whilst also keeping this flexibility within the language.

At the moment this feature seems quite 'Javascript-y' and not very 'Dart-y'. Would it help if I could post this as a feature request somewhere?

Thanks

Daniel Joyce

unread,
Jun 29, 2015, 3:22:56 PM6/29/15
to mi...@dartlang.org, tom....@gmail.com, lad...@gmail.com
Given this fails as expected in Java, but I have been bitten by this as well. Dart thus sadly may need a 'strict' mode if they are unwilling to tighten things up because "Easy interoperability with Javascript"

This type of arbitrary down cast is a HUGE source of bugs, and basically renders a whole chunk of Dart 'safety' moot.

Implicit un-typechecked downcasting should be disabled for everything but "dynamic".

--
For other discussions, see https://groups.google.com/a/dartlang.org/
 
For HOWTO questions, visit http://stackoverflow.com/tags/dart
 
To file a bug report or feature request, go to http://www.dartbug.com/new

To unsubscribe from this group and stop receiving emails from it, send an email to misc+uns...@dartlang.org.
--
Daniel Joyce

The meek shall inherit the Earth, for the brave will be among the stars.

Daniel Joyce

unread,
Jun 29, 2015, 3:24:21 PM6/29/15
to mi...@dartlang.org, tom....@gmail.com, lad...@gmail.com
I mean, I don't understand what this feature gives. And actually, its a upcast at the call site of b(x), where x is upcast to ClassTest

Jim Trainor

unread,
Jun 29, 2015, 3:50:03 PM6/29/15
to mi...@dartlang.org
I have to disagree that this is a huge source of bugs. I have a large, and growing daily, base of Dart code written over the last couple of years. This never comes up as a problem.

Perhaps it generates some cognitive dissonance and the discomfort leads to this feeling that it will cause many bugs.

Pick any language that is used for real work. There will be many feature that are useful but come with some risk of errors or misuse (C++ anyone!).


Daniel Joyce

unread,
Jun 29, 2015, 3:52:04 PM6/29/15
to mi...@dartlang.org
It is incredibly unsound as part of a type system. Its a big gaping hole, and leads to hard to find bugs unless Dart Lint perhaps could at least warn ( or even optionally FAIL ) when it encounters it.

Jim Trainor

unread,
Jun 29, 2015, 4:03:58 PM6/29/15
to mi...@dartlang.org
All things considered, based on my own 42K lines of Dart code.... it doesn't bother me in the slightest.  Based on my experience I simply cannot agree it causes any major issues.  I honestly cannot think of a case where it caused a problem for me.


Bob Nystrom

unread,
Jun 29, 2015, 4:10:35 PM6/29/15
to General Dart Discussion, Tom Yeh, Ladislav Thon
On Mon, Jun 29, 2015 at 12:24 PM, Daniel Joyce <daniel....@gmail.com> wrote:
I mean, I don't understand what this feature gives.

The motivating example that I heard was querySelector(). That method nominally returns an Element. In practice, you often know what subclass it returns and want do treat the result as that subclass. For example:

CanvasElement canvas = querySelector("canvas#thing");

If Dart didn't allow implicit downcasting, this would cause a warning. You would have to do:

CanvasElement canvas = querySelector("canvas#thing") as CanvasElement;

Implicit downcasting addresses that. Of course, it doesn't address subexpressions. Even though this works in Dart:

CanvasElement canvas = querySelector("canvas#thing");
canvas.requestFullscreen();

This does not:

querySelector("canvas").requestFullscreen();
 
Also, the set of places where a function nominally returns a supertype and the user knows what concrete subtype it will returns, and the subtype has extra methods is pretty small. I've never found it a significant enough problem to be worth blowing a big hole in the type system.

I'd rather just to an explicit downcast in those few cases and make my intent clear. It would also be straightforward to tweak our APIs to make things like querySelector() easier to statically type. For example:

var canvas = CanvasElement.queryFrom(document, "#thing");

Or, if we had generic methods:

var canvas = querySelector<CanvasElement>("#thing");

In my own APIs, I definitely do not expect users to rely on implicit downcasting. Almost no other language has this, and it's really weird and unfamiliar even to fairly experienced Dart programmers.

And actually, its a upcast at the call site of b(x), where x is upcast to ClassTest

That's a downcast. "Up" means toward supertypes and the top type (Object), and "down" means toward subtypes.

Cheers!

- bob

Daniel Joyce

unread,
Jun 29, 2015, 9:45:15 PM6/29/15
to mi...@dartlang.org

Well of course you need to cast in those cases justbas you would have to cast in java.
So the argument is convenience? I mean why don't we throw all typing away then and just use JavaScript style rules since that is even more convenient.

As it is I cast anyways because of the warnings, so what is the point?


--
For other discussions, see https://groups.google.com/a/dartlang.org/
 
For HOWTO questions, visit http://stackoverflow.com/tags/dart
 
To file a bug report or feature request, go to http://www.dartbug.com/new

To unsubscribe from this group and stop receiving emails from it, send an email to misc+uns...@dartlang.org.

Lasse R.H. Nielsen

unread,
Jun 30, 2015, 2:10:05 AM6/30/15
to mi...@dartlang.org, Tom Yeh, Ladislav Thon
On Mon, Jun 29, 2015 at 10:10 PM, 'Bob Nystrom' via Dart Misc <mi...@dartlang.org> wrote:

On Mon, Jun 29, 2015 at 12:24 PM, Daniel Joyce <daniel....@gmail.com> wrote:
I mean, I don't understand what this feature gives.

The motivating example that I heard was querySelector(). That method nominally returns an Element. In practice, you often know what subclass it returns and want do treat the result as that subclass. For example:

CanvasElement canvas = querySelector("canvas#thing");

If Dart didn't allow implicit downcasting, this would cause a warning. You would have to do:

CanvasElement canvas = querySelector("canvas#thing") as CanvasElement;

Implicit downcasting addresses that.

While this was designed before I worked on Dart, it's not my understanding that the implicit down-cast was introduced to handle any particular case. It was simply the (only) way to do down-casts, and the language was designed for it.
It was the "a list of apples is a list of fruits" argument in reverse. Sometimes you just know that your fruit is an apple, and you don't have to go through any extra steps to tell it to the static type system - you just assign it to an Apple variable, and you are done. That is the cast, just as surely as if you had written an explicit cast - which would be just as impossible to test statically, and would fail just as fast in checked mode.
So you could say that assigning to a sub-type variable *is* the "explicit" cast.

Originally there was no cast operator, so there was no other way to do a down-cast.

/L 'and the `as` operator is pretty useless`.
--
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

Ladislav Thon

unread,
Jun 30, 2015, 3:06:24 AM6/30/15
to Lasse R.H. Nielsen, General Dart Discussion, Tom Yeh
Originally there was no cast operator, so there was no other way to do a down-cast.


It was. The Object class used to have a getter called dynamic that returned this, but its static type was Dynamic. And IIRC, you could always assing [Dd]ynamic to anything without warning.

LT

Lasse R.H. Nielsen

unread,
Jun 30, 2015, 3:10:35 AM6/30/15
to Ladislav Thon, General Dart Discussion, Tom Yeh
On Tue, Jun 30, 2015 at 9:06 AM, Ladislav Thon <lad...@gmail.com> wrote:
Originally there was no cast operator, so there was no other way to do a down-cast.


It was. The Object class used to have a getter called dynamic that returned this, but its static type was Dynamic. And IIRC, you could always assing [Dd]ynamic to anything without warning.

Ack, you could go through dynamic. I'm not sure I'd call that "casting" - it feels much more like *erasing* the type :)
 
/L

Benjamin Strauß

unread,
Jun 30, 2015, 5:39:47 AM6/30/15
to mi...@dartlang.org, tom....@gmail.com, lad...@gmail.com
Am Montag, 29. Juni 2015 22:10:35 UTC+2 schrieb Bob:

Or, if we had generic methods:

var canvas = querySelector<CanvasElement>("#thing");

Would this be added when/if Dart gets generic methods? This looks like a useful addition. 

Jim Trainor

unread,
Jun 30, 2015, 1:50:09 PM6/30/15
to mi...@dartlang.org

reductio ad absurdum doesn't help the argument.


Even without a down cast one can write code to access the properties and methods of the specialized class, it will run fine, and will produce no analyzer warnings if the analyzer did not have enough information to comprehend the types you are accessing.  That's Dart - if that's what you want it to be. For those that wish to have strict and traditional type enforcement there are options such as GWT.


The following is okay in Dart:


void blah(SomeBaseType x) {

  SomeSpecializedType x = y; // implicit cast

  y.doSomethingSpecial();


  // Also works in dart. No analyzer warning if x was declared "var", "dynamic",

  // or had not type annotation at all

  x.doSomethingSpecial();  

}


... and the exact same cast happens in countless lines of Java and C++ differing only by the Java cast or C++ dynamic_cast. Java and C++ may fail on the cast at runtime. Dart may fail on the cast in check mode. In unchecked mode it may get further and fail on a unknown property access.



On Mon, Jun 29, 2015 at 9:44 PM, Daniel Joyce <daniel....@gmail.com> wrote:

 snip 

I mean why don't we throw all typing away then and just use JavaScript style rules since that is even more convenient.

snip

Günter Zöchbauer

unread,
Jun 30, 2015, 3:25:17 PM6/30/15
to mi...@dartlang.org
ddc is strict, maybe this is covered as well
AFAIK ddc is currently integrated into analyzer 
Reply all
Reply to author
Forward
0 new messages