The return type Dynamic of a function

Hej guys !

I noticed something “special” with Dynamic return type of a function.

Let’s take this example : Try Haxe!

class Test {
  static function main() {
    var o = foo();
    $type( o );		// String
  }
  
  static function foo() : String{
		return null;
  }
}

As you can see o is bound to String, nothing special here.

Now, let’s take this example : Try Haxe!

class Test {
	static function main() {
		var v = foo(); // foo explicitly return type is Dynamic, but v is not
		v = "bar";
		// v = true; // <-- Compiler fails : Bool should be String
		$type(v); // String

		//

		var v:Dynamic = foo();
		v = "bar";
		v = true; // <-- It's ok
		$type(v); // Dynamic
	}

	static function foo():Dynamic {
		return 1;
	}
}

It can seem weird but it doesn’t hurt me much.
I can imagine that it’s a wanted Haxe behaviour, a special case for Dynamic that is kind of hell’s type :smiley:

But can anyone confirm me that it’s a really wanted bahaviour or maybe it’s just a “bug” ?
Because, maybe I’v misunderstood @Simn answer here : Possible inconsistency in the return type Dynamic of a function · Issue #12057 · HaxeFoundation/haxe · GitHub but he seems to say that the var “will later be bound to Dynamic”, what IMHO is wrong, so I just don’t know what to think : is it a wanted behaviour or as @Simn says it should be bound later to Dynamic and is not, so it would be kind of bug.

Please believe me that I don’t want to create a big debate or change things, if it’s a wanted behaviour it’s ok for me, I just want to be sure for this case in order to understand better how Haxe works.

Thanks for reading me and if someone is sure that it’s wanted behaviour (not only believe), if you please, answer me.

Cheers,

I can make sense of it so it will not be as weird, at least for me its wnated behaviour, This will not answer your question whether this was the wanted behavior of the implementatior, probably he didn’t wanted anything he didn’t thought about that.

I think the rule of precedence is

1. Concerete dynamic decleration `var s:Dynamic` -> forced dynamic
2. First use of variable with type `my_dyn="str";` -> forced type
3. implicit dynamic (such as return from function) used as dynamic -> is a (dynamic) Unknown<T> (thanks Michal for correcting)

These rules allows us

  1. to use Json.parse and specify the type, or let haxe check for inconsistncies on how we use the type.
  2. check for array literals such as var a=[1,2,3,4,5,"a"]; while allowing to opt out by declaring var a:Dynamic=[1,2,3,4,5,"a"];

So unless you opt in for dynamic, haxe thinks that it is our favor to figure out the type, even the function didn’t guarentee to return a specific type, we can make our calling code safer by assuming a type. (and if the asuumption fails, we could blame the function for using dynamic).

Haxe could potentionally add an official type called Unknown that we can use for functions like Json.parse, then dynamic could get mroe power.

WOrth to mention here the Any type that will be better with asuumptions.

Thanks for your reply but I also can make sense of it, it’s not the problem here.
I just want to be sure it’s a wanted behaviour and that what @Simn said was a mistake (unless I misunderstood what he said, it’s possible with my bad english…)

class Test {
  static function main() {
    var o = haxe.Json.parse( "1" );
    $type( o );		// Unknown<0>
    o = "str";		// <-- Bound to String
    $type( o );		// String
    
    var o : Dynamic = haxe.Json.parse( "1" );
    $type( o );		// Dynamic
    o = "str";		// <-- Not bound to string, leaves Dynamic
    o = true;		// <-- Not bound to bool, leaves Dynamic
    $type( o );		// Dynamic
  }
}
  1. implicit dynamic (such as return from function) used as dynamic → is NOT a dynamic

It stays Unknown<0> so a monomorph and it will be bound to the first type assigned !

Thanks for correcting, it remains an unknown even after passing as a dynamic, I corrected my answer.

So considering what you say, I would prefer these function like Reflect.field or haxe.Json.parse or any custom function that returns unspecified type, I would prefer them not having a specified return type or maybe return type to be Any. This way it’s our job to type them correctly, like you promote an Any.
But not having explicitly return type Dynamic that brings confusion.