-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
case when covering all types of a type restricted variable shouldn't need an else case #1846
Comments
The recrusive part is not important: def encode(value : Int|Array) : String
case value
when Int
"int"
when Array
"array"
end
end
encode([1,2,3]) |
As a workaround, try something like http://carc.in/#/r/lh6: def encode(value : Int|Array) : String
case value
when Int
"int"
when Array
"array"
else
raise ""
end
end
encode([1,2,3]) |
Or def encode(value : Int|Array) : String
ret = case value
when Int
"int"
when Array
"array"
end
ret.not_nil!
end |
You can use method overloads for this: def encode(value : Int) : String
"int"
end
def encode(value : Array) : String
str = "list:("
value.each do |v|
str += encode(v)
end
str += ")"
end
puts encode([1, 2, 3]) But yes, we need something that will tell the compiler "I know this case has all types covered, tell me if not". As a side note, constructing strings this way is very slow, use def encode(value)
String.build { |io| encode(value, io) }
end
def encode(value : Int, io)
io << "int"
end
def encode(value : Array, io)
io << "list:("
value.each do |v|
encode(v, io)
end
io << ")"
end
puts encode([1, 2, 3]) |
There's a way to do this without any additional language feature. For example: def assert_empty_type(obj : T)
{% if T.union? %}
{{ raise "unhandled types: #{T.union_types.join(", ").id}" }}
{% else %}
{{ raise "unhandled type: #{T}" }}
{% end %}
end
def encode(value : Int | Array) : String
case value
when Int
"int"
when Array
"array"
else
assert_empty_type value
end
end
index = "foo".index('o')
case index
when Nil
puts "was nil"
when Int32
puts "was int"
else
assert_empty_type index
end This works. If we remove one branch we get a compile error: def assert_empty_type(obj : T)
{% if T.union? %}
{{ raise "unhandled types: #{T.union_types.join(", ").id}" }}
{% else %}
{{ raise "unhandled type: #{T}" }}
{% end %}
end
index = "foo".index('o')
case index
when Nil
puts "was nil"
# when Int32
# puts "was int"
else
assert_empty_type index # Error: unhandled type: Int32
end That's a way to make sure you cover all types. This works because when index is being filtered out, after discarding I'd even consider adding this in the standard library, maybe with a better name, and of course trying to improve the error message which is now a bit cryptic. |
@asterite: totality checking is an awesome feature of crystal. 🍕 I really think that totality checking is a must have when you want to write future-proof code in the presence of open types collections/unions. How about a new
I understand new syntax has a heavy cost, but I think crystal should push programmers to use totality checking when appropriate. It will yield better code quality, catch more errors, and really ease some kind of refactoring / or new cases additions over large codebases . if you don't like new syntax, how about chaning
|
One problem is that not all things can be statically checked for totality. For example: x = rand < 0.5 ? :blue : :red
case x
when :red; puts "red"
when :blue; puts "blue"
else # this is now required simply because the compiler can't
# be smart enough to detect all cases
end If limited to types and enums only, +1 |
I'd love to see this by default for Enums and Types. I actually just stumbled upon this trying out Crystal and wondering why my return type is Any status update on this feature? |
I really like the possibility of solving this using the index = "foo".index('o')
case index
when Nil
puts "was nil"
when Int32
puts "was int"
else impossible!(index)
end The alternative is to make this a language construct, possibly with a Overall I think the top-level method is my favourite. |
I would love to see this feature as well. I like the idea of automatically doing this for enums and types, but if that's too hard/unwanted, then I like the |
Resolved by #8424 |
i have a function that contains a single case…when construct that covers all allowed types. if the function calls itself the compiler determines the case expressions return type as String?
code:
error message:
playground: http://play.crystal-lang.org/#/r/lgo
The text was updated successfully, but these errors were encountered: