Cannot cast an interface in Javascript

102 views
Skip to first unread message

Adrian Martinez

unread,
Feb 5, 2013, 6:22:12 AM2/5/13
to haxe...@googlegroups.com
Hi folks,

I got an error in javascript: 
 

var data = cast( {}, ITableName );
data
.field1 = "value1";
data
.field2 = "value2";
data
.field3 = "value3";
 
 
// error message:
 
uncaught exception
: Cannot cast {
 
} to {
        __name__
: [bkh,database,interfaces,ITableName]
}



I'm trying to cast an empty object from an interface
It works in php but not in javascript
Does anyone know how I could fix this?

Greetz, Adrian

Juraj Kirchheim

unread,
Feb 5, 2013, 8:31:52 AM2/5/13
to haxe...@googlegroups.com
That's not supposed to work, so it's actually a bug in the PHP implementation of typed casts. An empty object does not implement any interfaces and the cast is thus invalid. Interfaces are explicitly contracts, that are not only present at runtime, but also implemented at compiletime.

Think of cast(e, T) as: 

    function cast<Src, Dest>(x:Src, d:Type<Dest>):Dest
        return 
           if (Std.is(x, d)) untyped x 
           else throw '$x is not $d';

I believe some platforms actually implement it along these lines. The point is, the runtime type check (i.e. `Std.is`) will not return true, and you will thus get the error.

However, you can use anonymous types instead (the compiletime equivalent of ducktyping if you will):

    var data: { field1:String, field2: String, field3: String } = untyped {}; //or `cast {}` if you wish

And you can use a typedef:

    typedef TableName = { field1:String, field2: String, field3: String }

Thus allowing you to do:

    var data:TableName = untyped {};

But the following two variants are both better, because they don't involve slapping the type system in the face:

1. Initialize directly: 

    var data:TableName = { field1: "value1", field2: "value2", field3: "value3" };

2. Use optional fields:

    typedef TableName = { ?field1:String, ?field2: String, ?field3: String }
    var data:TableName = {};

Please note the difference: In the first example you establish an explicit contract, that a TableName *must* have these fields defined and you thus honor it. In the second example you say the fields are optional and therefore the compiler will let you add them later as needed.

Regards,
Juraj

Adrian Martinez

unread,
Feb 5, 2013, 9:01:11 AM2/5/13
to haxe...@googlegroups.com
Hi Juraj,

I understand that's not possible to implement an interface on an empty object.
I'm using this method to try making the object type safe.
Eventually the following code did the job for me:

var data:TableName = untyped {};

and

var data:TableName = cast{};

I want the object to be type safe for the haxe compiler, in JS it may easely be a dynamic object {}.

Thnx for the help.

Greetz, Adrian (EZ-wan)

Op dinsdag 5 februari 2013 14:31:52 UTC+1 schreef back2dos het volgende:

Juraj Kirchheim

unread,
Feb 5, 2013, 9:29:49 AM2/5/13
to haxe...@googlegroups.com
On Tue, Feb 5, 2013 at 2:01 PM, Adrian Martinez <adria...@gmail.com> wrote:
Hi Juraj,

I understand that's not possible to implement an interface on an empty object.

That's no exactly true. With knowledge of how classes and interfaces and instance are represented on a platform, you may well be able to do that. In the case of the JavaScript target, this is rather easy to accomplish. However I would discourage such hackery ;)
 
I'm using this method to try making the object type safe.

I understand that. However as I pointed out, interfaces are not meant for that. Anonymous types are.

[,,,]
I want the object to be type safe for the haxe compiler, in JS it may easely be a dynamic object {}.

The point is, if you want your code to be type safe, you should avoid cast or untyped. Both variants I proposed work without it and are therefore better in the long run.

In your code, you force the compiler to accept the fact that an empty object has a field `field1`, which is certainly untrue until you assign it. That means the type safety of your program is demoted to being a side effects of your code. If for example you add a `field4` to your type declaration but forget to initialize it in the code, the compiler will not be able to determine that and you're in for some delightful surprises at runtime ;)

Regards,
Juraj

Cauê Waneck

unread,
Feb 5, 2013, 11:46:52 AM2/5/13
to haxe...@googlegroups.com
also the typedef approach Juraj suggested on his previous post will be strictly typed and semantically correct. Such code as you posted, with "cast", will fail on some targets like C++, Flash 9+, Java and C#

2013/2/5 Juraj Kirchheim <back...@gmail.com>

--
To post to this group haxe...@googlegroups.com
http://groups.google.com/group/haxelang?hl=en
 
---
You received this message because you are subscribed to the Google Groups "Haxe" group.
To unsubscribe from this group and stop receiving emails from it, send an email to haxelang+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Adrian Martinez

unread,
Feb 5, 2013, 12:55:01 PM2/5/13
to haxe...@googlegroups.com
Hi Juraj,

Thnx for the explanation.
I will digg into the typedef method to make my code more reliable.
At the moment my code does what I want, so I'm happy.

Greetz, Adrian

Op dinsdag 5 februari 2013 14:31:52 UTC+1 schreef back2dos het volgende:
That's not supposed to work, so it's actually a bug in the PHP implementation of typed casts. An empty object does not implement any interfaces and the cast is thus invalid. Interfaces are explicitly contracts, that are not only present at runtime, but also implemented at compiletime.

Adrian Martinez

unread,
Feb 5, 2013, 12:59:56 PM2/5/13
to haxe...@googlegroups.com
Hi Cauê,

I will digg into the typedef method to make my code more reliable.
At the moment my code does what I want, so I'm happy.
Flash 9 works too btw: var foo : ISomething = cast{ }

Greetz, Adrian

Op dinsdag 5 februari 2013 17:46:52 UTC+1 schreef Cauê Waneck het volgende:
Reply all
Reply to author
Forward
0 new messages