Open nitnelave opened 9 months ago
I'll have to check how Result<T,E> gets turned into a lua value but without having looked into it yet I fear that just implementing ToTypename is not good enough (and even if it is, that the resulting .d.tl files that use it will not work)
edit: Probably a good idea to explain why the .d.tl file won't work.
Basically, I expect that it becomes a structure that boils down to table | table
which is not (yet) allowed in teal.
The result gets turned into one or two values: Ok(T) -> T
, Err(E) -> nil, E
that.... is not a nice type to work with >_<
it means that the type actually is a (T) | (nil, E)
which, isn't a thing as lua doesn't have tuples.
So, we have to simplify it until it is valid. Which will get us (T, nil) | (nil, E)
-> (T | nil) , (nil | E)
-> T , E
And this will work.... until it doesn't. Because, once again, tuples.
If you return a (Result<T,E>, F)
then in lua you will either get a T, F
back or a nil, E, F
. So, (T,F) | (nil, E, F)
. Which, isn't a thing so we have to simplify it until we get (T | nil), (E | F), (F | nil)
.
Even worse, E | F
may not even be valid if both use the same lua primitive (so, if both are userdata, or a table, etc)
Yeah, I'm not sure how they want to handle it when you return a result and something else. It's not well defined in Lua either, what is the interface when you return 3 values but also potentially an error? Sometimes you have to reach for instanceof (or typeof or however it's called).
I think they have an escape hatch: Anything that implements IntoLua implements IntoLuaMulti (potentially gets converted to several values). But Result only implements IntoLuaMulti if both T and E implement IntoLua, so as a single value. And I bet that tuples only implement IntoLuaMulti if each value implements IntoLua, which Result doesn't. So that saves you from the situation you were afraid of, and it becomes a (T, E).
If you want something more complex as a customer, you can make your own type that contains a Result and a F (and G, ...) and implement yourself IntoLuaMulti and FromLua, deciding on the API at that point.
mlua solves another issue than the one I run into.
Mlua just wants to make sure that a given value can be converted into a lua value. And a (Result<T,E>, F)
can indeed become a lua value for as long as T,E and F all implement IntoLua (well, 2 or 3 depending on the variant of Result). That is not the problematic part.
The problematic part comes from writing the correct type.
Lua, has no tuples. So, there is no way to write (T, E) | (F, G)
, nor T | (E, F)
. Or any other variant of that. You have to weave the 2 sides together. So (T, E) | (F, G)
becomes (T | F) , (E | G)
. And so far, that is still easy.
However, once the sides become unbalanced, which is the case with Result<T,E> it becomes very messy.
I still think I will implement Result<T,E>
when I have the time however I will also add a check on Union(T,E)
so it produces a runtime error if one side is a Tuple.
AFAIU you can't write (Result<T, E>, F)
in mlua (and convert it to a value): you'd have to make a custom type with a custom conversion operator, and a custom ToTypename
. Or are you worried about other runtimes than mlua?
EDIT: Oh, interesting, you can write (F, Result<T, E>)
since only the last value converts to a multiple values: https://docs.rs/mlua/latest/mlua/trait.IntoLuaMulti.html
With
mlua
,Result
implementsIntoLuaMulti
(as long as the arguments implementIntoLua
). However, that breaks with tealr since it doesn't implementToTypename
. And we can't implement it in a client crate, since we own neither the struct nor the trait.Could you implement
ToTypename
forResult
?