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

enum class like in Rust #2787

Open
kostya opened this issue Jun 9, 2016 · 6 comments
Open

enum class like in Rust #2787

kostya opened this issue Jun 9, 2016 · 6 comments

Comments

@kostya
Copy link
Contributor

kostya commented Jun 9, 2016

i think this nice feature to add, i think about this macro:

enum_class Op, 
  Inc(val : Int32), 
  Move(val : Int32), 
  Loop(loop : Array(Op)), 
  Print

which expanded to:

module Op
  record Inc, val : Int32
  record Move, val : Int32
  record Loop, loop : Array(Op::T)
  record Print

  alias T = Inc | Move | Loop | Print
end

but if it would possible that Op be resulted type, not Op::T (thats nicer)?

ops = [] of Op
ops << Op::Inc.new(1)
@lbguilherme
Copy link
Contributor

I may be wrong, but the languages that support it doesn't support union types as Crystal do. The functionality seems to overlap, only with different syntax. Do you have an user case where using this kind of enums would be significantly better than simply creating records/classes for each element and using them?

@asterite
Copy link
Member

asterite commented Jun 9, 2016

Also:

abstract struct Op; end
record Inc < Op, val : Int32
record Move < Op, val : Int32
record Loop < Op, loop : Array(Op)
record Print < Op

That's what you traditionally do in OOP languages. That has the benefit that you can use case op; when Inc, or you can add methods to Op to perform polymorphic dispatch.

What we do need is a way to have case check that all possible cases are covered. The same would apply to an enum. But that's a different issue (I think there's an existing issue for that).

@kostya
Copy link
Contributor Author

kostya commented Jun 9, 2016

i used it here: kostya/benchmarks@a4f403f and it give 20% performance, comparing to symbols

@bcardiff
Copy link
Member

@asterite #285 is the issue you refer to.
I think is a nice use case to have what @kostya propose. It's like a algebraic type in Haskell. Plain:
data Op = Inc Int | Move Int | Loop [Op] | Print

But is useful as long as you do not need to reopen each of those types. There you need to know what is the macro doing and is a leak of abstraction.

The fact that they are different types allow us to use method & cases to match the constructor. But it lacks of proper pattern matching. If we reach proper pattern matching then it might have more sense definitely.

Even so, the question is if it is a good idiom for crystal when used just as a bunch of records.

I don't know if in the compiler itself would be useful. But it seems like a nice helper to have IMO.

@asterite
Copy link
Member

@kostya The performance improvement is probably because before the change you switched over the symbol, and then you used as, which does a check against a type id. So, two checks. Using case ...; when Inc just does one check.

@kostya
Copy link
Contributor Author

kostya commented Jun 10, 2016

i tried with two fields also record Op, op : Symbol, val : Int32, loop : Array(Op)?, but also slow

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

6 participants