Inconsistency with abstract type inference

39 views
Skip to first unread message

Marco Salamone

unread,
Jun 22, 2013, 7:28:46 PM6/22/13
to haxe...@googlegroups.com
I would like to be able to abstractly coerce some generic type as a bool without altering how the underlying type may be used. The flag needs to be set and not a function of the type. The main application here is being able to pack a bool type with a return value whenever necessary. I specifically do not want this bool to be a part of the underlying type nor do I want to obfuscate accessibility with wrapper objects.

The results provided are targeting Linux 64.

I have this so far,
abstract Flag<T>({value:T,flag:Bool})
{
 
public function new(value:T,flag:Bool) this = {value:value,flag:flag};
 
@:to public inline function toFlag():Bool return this.flag;
 
@:to public inline function toValue():T return this.value;
}

But the odd thing is...

 var a = new Flag<Int>(0,true);
 
var mc = function(a):Int return a;
 
 trace
(Std.is(a,Bool)); //false
 trace
(Std.is(a,Int));  //false
 
 
var j:Int;
 j
= a;                 //works
 j
= mc(a);             //works
 j
= a + 0;             //cannot add Flag<Int> and Int
 j
= Std.int(a)+0;      //works
 j
= cast(a,Int);       //invalid cast (runtime)


 
var i:Bool;
 i
= a;                 //works
 i
= i? true : false;   //properly evaluates to true.
 i
= a? true : false;   //always evaluates to false without error.
 i
= a < 0;             //cannot compare Flag<Int> and Int


I'm confused on why some of these behaviors are doing what they're doing.

When I define a function that accepts or returns a sub-type of Flag, it works properly with the binary operators. However, the binary operators won't do the type coercion themselves, even though they are functions with parameters that accept their given type. Nonetheless, Oddly, casting doesn't work, even though assignment with a properly declared type does work.

The ternary operator is also rather bizarre. When using non-bool type, ternary-if throws an error- which would be consistent with the other operators, but here it arbitrarily works and evaluates to false.

What do I need to do to get the proper functionality?

Simon Krajewski

unread,
Jun 22, 2013, 7:46:08 PM6/22/13
to haxe...@googlegroups.com
Am 23.06.2013 01:28, schrieb Marco Salamone:
I would like to be able to abstractly coerce some generic type as a bool without altering how the underlying type may be used. The flag needs to be set and not a function of the type. The main application here is being able to pack a bool type with a return value whenever necessary. I specifically do not want this bool to be a part of the underlying type nor do I want to obfuscate accessibility with wrapper objects.

The results provided are targeting Linux 64.

I have this so far,
abstract Flag<T>({value:T,flag:Bool})
{
 
public function new(value:T,flag:Bool) this = {value:value,flag:flag};
 
@:to public inline function toFlag():Bool return this.flag;
 
@:to public inline function toValue():T return this.value;
}

But the odd thing is...

 var a = new Flag<Int>(0,true);
 
var mc = function(a):Int return a;
 
 trace
(Std.is(a,Bool)); //false
 trace
(Std.is(a,Int));  //false
 
 
var j:Int;
 j
= a;                 //works
 j
= mc(a);             //works
 j
= a + 0;             //cannot add Flag<Int> and Int
 j
= Std.int(a)+0;      //works
 j
= cast(a,Int);       //invalid cast (runtime)


 
var i:Bool;
 i
= a;                 //works
 i
= i? true : false;   //properly evaluates to true.
 i
= a? true : false;   //always evaluates to false without error.
 i
= a < 0;             //cannot compare Flag<Int> and Int

The ternary on "a" might be a bug, please file an issue. From a quick look, the rest seems to work as expected.

Note that you can compile with -D dump=pretty to get a readable representation of what the compiler typed. This helps with understand and finding bugs.

Simon

Marco Salamone

unread,
Jun 22, 2013, 8:07:40 PM6/22/13
to haxe...@googlegroups.com
Is there a reason why the type coercion doesn't work on binary operators?

Simon Krajewski

unread,
Jun 22, 2013, 8:11:23 PM6/22/13
to haxe...@googlegroups.com
Am 23.06.2013 02:07, schrieb Marco Salamone:
> Is there a reason why the type coercion doesn't work on binary operators?

You can define @:op functions on abstracts to deal with that. Having
implicit casts there would make it too confusing, so I think it's better
to keep the rules simple and let the type author do a bit more work by
being explicit.

Simon

Marco Salamone

unread,
Jun 22, 2013, 8:31:16 PM6/22/13
to haxe...@googlegroups.com
I'm more curious why. Other functions coerce as expected, why don't operators? It seems like an inconsistency that operators wouldn't coerce in the same way that normal functions do.

Also- given that the abstract I've defined uses a type parameter, I'm not sure how I would go about defining static @:op methods when they need to take a type parameter as a type.




Simon

--
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 a topic in the Google Groups "Haxe" group.
For more options, visit https://groups.google.com/groups/opt_out.



Simon Krajewski

unread,
Jun 22, 2013, 9:09:22 PM6/22/13
to haxe...@googlegroups.com
Am 23.06.2013 02:31, schrieb Marco Salamone:
I'm more curious why. Other functions coerce as expected, why don't operators? It seems like an inconsistency that operators wouldn't coerce in the same way that normal functions do.

Because the fact that an abstract type can be cast to a numeric type does not necessarily imply that all binary operations defined for that type make sense for it.

If you had an abstract Decibel(Float) to Float, your suggestion would allow adding an arbitrary Float value to your Decibel without respecting its logarithmic scale. In a similar fashion, using logical operators on a Fixed16 (https://gist.github.com/deltaluca/5413225) would mess up its data representation.

Simon
Reply all
Reply to author
Forward
0 new messages