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

Language: traits or type classes #2025

Open
spotandjake opened this issue Feb 14, 2024 · 0 comments
Open

Language: traits or type classes #2025

spotandjake opened this issue Feb 14, 2024 · 0 comments

Comments

@spotandjake
Copy link
Member

spotandjake commented Feb 14, 2024

Opening this for discussion and ideas surrounding type classes, traits or a similar alternative. This is a low priority feature and will likely not be implemented any time soon, if at all.

Currently in grain if you want a function to work on multiple data types, you don't really have an option besides wrapping your data in an adt which creates a performance bottleneck and increases code complexity. In internal cases such as print, marshal, toString and == we use unsafe matches and open types to provide functionality for multiple types through one function.

It would be beneficial if we could provide type-specific impl and let the compiler convert these function calls to each type of implementation call.

Some functional ideas include rusts trait system and haskells type classes

The benefits of this would be:

  • More performant code, as we do not need to do all the runtime type matching.
  • Our internal functions such as print, toString and == would be safer and more maintainable.
    • We might want to autogenerate a toString impl on types that don't specify one to maintain a good developer experience.
  • We could avoid runtime type information in a lot more cases (Our Number type would still be a problem, i.e we probably couldn't put a float64 represented as a number into a wasm local), but we could avoid tagging as the impl would know what type it's operating on.
  • We can write more generalized code as an example, the print function just needs to take a type that has a print impl and call its impl.

Ideas:

  • It would be rather annoying to have to write an impl for print, toString, == and the such for each type a user makes (Specifically relating to records) so we might want to autogenerate these impls and allow the user to override them.

Notes:

  • I feel that a big problem when reading Rust's code is the fact that an impl doesn't need to be implemented near the type definition while this allows for you to better organize code I think it makes understanding the full codebase a lot harder without reading the entire thing. so it would be nice if we could somehow keep impls near their type. (good LSP support could also help here, but shouldn't be a crutch).
  • We may want to avoid the a.test() syntax, we seem to attract a lot of OOP devs, specifically JS devs and I think the method-looking syntax might cause a lot of confusion, it would be beneficial if something like toString(t) would be converted by the compiler into t.toString(), I think this might need to be workshopped a little as if the user defines a toString function in the scope how do we know which one the user wants to use. maybe we add a symbol to denote it something like toString!(t) but there are certainly issues with this.

Question:

  • Could we allow for safer use of WasmXX types with this? for example, if we added a toString impl to WasmF64 there is no good reason it needs to follow the standard grain abi where every type is a WasmI32.

Expansions:

  • We have talked about implementing iterators before specifically when it comes to slicing up arrays efficently, from what I understand rust implements iterators through the trait system as seen here
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant