ponyc
ponyc copied to clipboard
Allow finite recursive type aliases
When working on a pure Pony implementation of JSON parsing and encoding, I've run into the following issue:
When compiling:
type JsonNull is None
type JsonBoolean is Bool
type JsonString is String
type JsonNumber is F64
type JsonArray is Array[JsonEntity]
type JsonObject is Map[JsonString, JsonEntity]
type JsonEntity is
( JsonNull
| JsonBoolean
| JsonString
| JsonNumber
| JsonArray
| JsonObject)
I get type aliases can't be recursive errors. I understand that these type aliases are recursive, but not sure if there is another way to implement this other than using recursive types. Is there a way I can refactor these aliases to avoid the compiler warning? Note that I want to avoid using "container" objects that compose the builtin pony ones - I'd like to operate on builtin pony objects directly, just under aliased names. If not, is it possible to lift this restriction in the compiler by detecting the recursion and responding appropriately?
Unfortunately there are technical problems with allowing actual recursive aliases. It may well be possible to do this at some point if there's a big call for it, but it won't be easy and so is unlikely to happen any time soon.
The way the standard library implementation of JSON works (which isn't released yet, sorry it will be soon) is to have wrapper types around the complex JSON types (array and object) but not the others.
type JsonType is (F64 | U64 | Bool | None | String | JsonArray | JsonObject)
class JsonArray
var data: Array[JsonType]
class JsonObject
var data: Map[String, JsonType]
@andymcn - Thanks for the info. Also, If you're already working on a pure Pony JSON implementation, I won't spend any more time on mine, then. I was going to offer it for inclusion into the standard library when it was done, but it sounds like there is no need.
Still, I think there are probably other cases where this issue will come up. I've seen it once before when trying to make a function that can print "inspect"-style strings for collection types. I was unable to make a function that accepts nested collections, which is a pretty major limitation. So if in the future it is possible I would like to know about it and I'd like to leave this issue open for now.
Looking forward to it, tried to write a TNetString parser/dumper, at the optimization state the compiler throws a illegal machine instruction exception when i don't immediately return from a type match..
match type
| "," => String
| "#" => Integer
values chosen randomly, as soon as a second match is there the optimization phase crashes, when i do it like this it works.
match type
| "," => return String
| "#" => return Integer
values again chosen randomly, only the return matters.
This also happens with
if
elseif
else
end
Ill try to make a repro soonish, but it will be quite long.
@Asmod4n, I can't reproduce the problems you mention, but I'm not sure I understand exactly what situations you're talking about.
Please give a complete program (or at least a complete function) that displays this problem and create a new issue for it.
Thanks.
Cannot write a repro, don't even have the code in my backups :/ It's most likely because i am using a beta version of Xcode.
The problem is we are disallowing all type alias recursion, when we should only disallow infinite type alias recursion. For example:
type A is Array[A] // infinite recursion, illegal
type B is Array[C]
type C is (Array[B] | None) // mutual recursion, but legal
Checking this is certainly possible, but non-trivial. But we should do this.
@SeanTAllen - I don't think this should be labelled as "turn into rfc" - it doesn't introduce any new API or concepts, it simply makes the compiler able to understand a class of programs that the current implementation cannot. I'm going to remove that label.
Also, I see this was labelled as "enhancement" before we added the various levels of work for "enhancement" - I'm going to mark it as "ready for work", since @sylvanc has explained what needs to be done, and it's just a matter of someone coming up with a workable implementation.
I'm tagging this as "needs discussion during sync" as I'd like to talk about what we need to do to make this happen.
The first step is to no longer flatten type aliases. Particularly, in names.c:names_typealias - don't do that :) Instead, we should promote type aliases to a first-class thing in the AST.
After that, there will be a significant amount of work adding type aliases as first-class concepts to subtype.c, matchtype.c, and reify.c - and other places as well, although I think those are likely to take the most work. Effectively, type aliases need to be usable wherever we would use a type.
The last step is to detect, disallow, and report infinite recursion. This should be relatively easy. The key I think is that type parameters don't necessarily cause infinite recursion, as in the mutual recursion example above (which should be allowed).
This will also improve error reporting, as errors involving type aliases can be reported with the alias name, rather than the flattened type (which is often tediously long).