dao
dao copied to clipboard
Transitive non-nominative type information is getting lost
m = {
(enum<a,b>)$a -> 5,
$b -> 7,
}
io.writeln(std.about(m))
m2 = (map<@K, @V>)m
io.writeln(std.about(m2))
m3 = m2.associate { ( ((string)X)[1:], Y ) }
io.writeln(std.about(m3))
map<enum<a,b>,int>[0x1e5a720]:map<enum<a,b>,int>
map<enum<a,b>,int>[0x1e5a720]:map<@K,@V>
map<string,@V2>[0x1e65580]:map<string,@V2>
This is very inconvenient. I would need the last line to be map<string,int>[0x1e65580]:map<string,@V2>.
That is actually the expected output. Because the real type for the map value is determined at compiling time according to Y in associate{}, where Y was determined to be of @V type.
To bring up a real scenario:
load web.json
y = {
(enum<a,b>)$a -> 5,
$b -> 7,
}
io.writeln(
json.serialize(y) { [obj]
switch (obj) type {
#case map<enum, @T>: # why doesn't this match enum<a,b>? empty enums doesn't make much sense on their own, so `enum' should be a "general" enum
case map<@K, @V>:
return (json.Data)obj.associate { ( ((string)X)[1:], Y ) }
default:
return (json.Data)"some mistake!"
}
}
)
[[Error::Type]] --- Invalid type:
casting from 'map<string,@V2>' to 'Data'.
In code snippet:
33 : GOTO : 0 , 25 , 70 ; 14; }
>> 34 : CAST : 18 , 9 , 26 ; 14; (json. Data)obj. associa...
35 : RETURN : 26 , 1 , 0 ; 14; return (json. Data)obj. ...
Raised by: __main__(), at instruction 34 in line 14 in file "/home/test/del/test.dao";
Called by: __main__(), at instruction 14 in line 10 in file "/home/test/del/test.dao";
The best solution in this case is to change case map<@K, @V>: to case map<@K, json.Data>:. But the intention was to match any map (disregarding key and value types) and then try to cast only that, which the json module can't cast on it's own. Thus only the key. It's also enough to put (int) casting in front of Y, but this is expected from the json module.
What would you recommend in general cases similar to this one? Such cases will occur on places with compound types composed from many different types and especially combined with recursive types.
There is another issue with code sections. The return type is not visible and if it's a complicated one, it would be handy to have a universal type called e.g. @Return, which would be alias to the return type of the code_section/routine/method it's written in. In the example above, the casting (json.Data)obj.associate... and (json.Data)"some mistake!" would become (@Return)obj.associate... and (@Return)"some mistake!" respectively. @Return would be useful in routines/methods as well, but it's much less needed, because the return type can be immediately clearly seen from the routine declaration (if there is none, @Return would have the value none). Maybe @Night-walker would be also interested in this.
That's a typing bug. The value returned from the code section is of type Data|list<any>|map<string,any>, so passing map<string,@T> should be successfully matched.
As for @Return, I guess it's needless since the type of the returned value is always known at compile time and there is no problem in specifying it directly.
I guess it's needless since the type of the returned value is always known at compile time and there is no problem in specifying it directly.
Yes, it's known in compile time, but I myself had problems with specifying the type directly already on several places, because I didn't remember them exactly (it's not always the case, that compound types have an alias like json module has the json.Data type). So it would be just a compile-time sugar.
Actually, there is no bug again:)
The casting failed because json::Data is a variant type. When casting to a variant type, at least one of the element types in the variant has to be compatible with source type. Here the closest type to map<string,@V> in json::Data is map<string,json::Data>, but they are not compatible (due to contra-variance issues). So the casting fails. If you use (map<string,json::Data) to do the casting, it will work.
Currently, when casting a variant type, if there are multiple element types compatible to the source type, the best one is chosen to do the cast. If none is compatible, the cast fails, even when explicit casting to an element type could succeed. The reason is that there is no good rule to decide which element type should be the best or intended target type.
Yes, it's known in compile time, but I myself had problems with specifying the type directly already on several places, because I didn't remember them exactly (it's not always the case, that compound types have an alias like json module has the json.Data type).
Understandable. I think we should not burden users with the task of deducing the types. In the case of code section method json.serialize()[], we could enhance it by serializing the value as usual and invokes the code section only when it does not know how to serialize a particular value.
Then in the above example, only the keys will be used to invoke the code section, and it will be much easier to handle, because the type of values passed to the section will be simpler. In fact, the code section will no longer need to handle aggregated types such as list and map, and the type cases will be more manageable.
Actually, there is no bug again:)
The casting failed because json::Data is a variant type. When casting to a variant type, at least one of the element types in the variant has to be compatible with source type. Here the closest type to map<string,@V> in json::Data is map<string,json::Data>, but they are not compatible (due to contra-variance issues). So the casting fails. If you use (map<string,json::Data) to do the casting, it will work.
I still don't understand why everything after Data in Data|list<any>|map<string,any> seems to be ignored when matching map<string,@V>. That's a variant type and one of the alternatives is compatible with the type being matched. What's wrong then?
I switched to yielding map keys in the code section (it's indeed simpler and more efficient), but the question about type matching still holds.
I still don't understand why everything after
DatainData |list<any>|map<string,any>seems to be ignored when matchingmap<string,@V>. That's a variant type and one of the alternatives is compatible with the type being matched. What's wrong then?
OK, this is indeed a bug. Now fixed.