Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement ToTypename for Result #86

Open
nitnelave opened this issue Jan 30, 2024 · 6 comments
Open

Implement ToTypename for Result #86

nitnelave opened this issue Jan 30, 2024 · 6 comments

Comments

@nitnelave
Copy link

With mlua, Result implements IntoLuaMulti (as long as the arguments implement IntoLua). However, that breaks with tealr since it doesn't implement ToTypename. And we can't implement it in a client crate, since we own neither the struct nor the trait.

Could you implement ToTypename for Result?

@lenscas
Copy link
Owner

lenscas commented Jan 30, 2024

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.

@nitnelave
Copy link
Author

The result gets turned into one or two values: Ok(T) -> T, Err(E) -> nil, E

@lenscas
Copy link
Owner

lenscas commented Jan 30, 2024

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)

@nitnelave
Copy link
Author

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.

@lenscas
Copy link
Owner

lenscas commented Jan 30, 2024

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.

@nitnelave
Copy link
Author

nitnelave commented Jan 30, 2024

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants