crystal lang : in case of a Class as a field
Clash Royale CLAN TAG#URR8PPP
crystal lang : in case of a Class as a field
I'm just writting an Exception, which should stores a Class
object as a field for the error message process.
Class
class BadType < Exception
getter should_be : Class
getter actual : Class
end
def feed(pet : Animal, food : Food)
raise BadType.new should_be: Cat, actual: pet.class if food == "fish" && !pet.is_a?(Cat)
end
But, Class
is abstract so cannot be used here as a field type.
Class
So, how to solve this in my case? I hadn't found any derived class of Class
, so does it mean one can never store a Class
object as a field? But here my problem is a meaningful usage for this (any type check depends on input may require this BadType
).
Class
Class
BadType
I'm not sure whether I missed something, so I came here first.
2 Answers
2
Class
can't (yet) be used as a ivar type. Maybe it never will, I don't know.
Class
But you can actually use generics for concrete data types, inferred from the arguments to the constructor:
# possible workaround
class Foo(T, U)
def initialize(@bar : T, @baz : U)
end
end
Foo.new String, Int32
I don't know your exact use case, but chances are you don't really need these values as classes. You probably can't do much with it anyway and drawing from your example I guess it's mostly for showing debugging information.
So it is very likely that just storing the names of the classes (as strings) would be a better solution for this problem.
# better solution
class Foo
@bar : String
@baz : String
def initialize(bar : Class, baz : Class)
@bar = bar.name
@baz = baz.name
end
end
Foo.new String, Int3
The generic arguments mean a new concrete type is created for every combination of classes used with Foo
. That can have an impact on compiler performance.
Foo
I would most definitely use strings for this. Even if you need the classes for some particularly processing later on, it's probably better to just map the strings to the constants using a macro-generated lookup table.
Try generics:
class BadType(ClassA, ClassB) < Exception
getter should_be : ClassA
getter actual : ClassB
def initialize(@should_be, @actual)
@message = "Bad type: should be #@should_be, actual is #@actual"
end
end
def feed(pet : Animal, food : Food)
raise BadType(Animal.class, Animal.class).new should_be: Cat, actual: pet.class if food == "fish" && !pet.is_a?(Cat)
end
class Animal
end
record Food, food : String do
def ==(other_food)
@food == other_food
end
end
class Cat < Animal
end
class Dog < Animal
end
feed pet: Dog.new, food: Food.new("fish")
Output:
Unhandled exception: Bad type: should be Cat, actual is Dog (BadType(Animal:Class, Animal:Class))
from /eval:11:3 in 'feed'
from /eval:29:1 in '__crystal_main'
from /usr/lib/crystal/crystal/main.cr:104:5 in 'main_user_code'
from /usr/lib/crystal/crystal/main.cr:93:7 in 'main'
from /usr/lib/crystal/crystal/main.cr:133:3 in 'main'
from __libc_start_main
from _start
from ???
Demo: https://carc.in/#/r/4pgs
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.