Reputation: 123
The program I'm writing is storing elements in a hash called grid
of type Position => LivingBeing | Thing
. This grid
is stored on a Map
and I would like this Map
to return the position of an element of class Apple
which is a subclass of Thing
.
However, when using typeof()
to get the class, I get LivingBeing | Thing
instead of the subclass Apple
Here is the Map
class:
class Map
@@grid = {} of Position => LivingBeing | Thing
def initialize()
end
# Add an entity to the grid
def add_entity(new_entity : LivingBeing | Thing)
@@grid[new_entity.position] = new_entity
end
# Return the position of an object of class "something"
def self.where_is?(something : Class)
# First attempt was to get the key by the value
# @@grid.key(something)
@@grid.each do |position, thing|
# Returns "thing #<Apple:0x55f1772085c0> at Position(@x=1, @y=2) is (LivingBeing | Thing)"
puts "thing #{thing} at #{position} is #{typeof(thing)}"
position if typeof(thing) == something
end
end
Here the Thing
class:
abstract class Thing
getter position
@name = "Unkown object"
def initialize(@position : Position)
end
end
class Apple < Thing
@name = "Apple"
end
Here the Position
struct:
struct Position
getter x, y
def initialize(@x : Int32, @y : Int32)
end
end
And here is the test I try to make it pass:
it "gives a random thing location based on its class" do
world = Map.new()
apple = Apple.new(Position.new(1, 2))
puts "Apple type : #{typeof(apple)}" # Returns "Apple type : Apple"
world.add_entity(apple)
position = Map.where_is?(Apple)
position.should eq Position.new(1, 2)
end
Is there some class method or function which could give the Apple
class?
Or is it a design issue?
Thank you for your answer !
Upvotes: 2
Views: 75
Reputation: 3175
You can use forall
to solve this:
# Return the position of an object of class "something"
def self.where_is?(something : T.class) forall T
@@grid.each do |position, thing|
return position if thing.is_a?(T)
end
end
and call it using Map.where_is? Apple
just like you wish.
This works because the type variable T
(introduced using forall T
) can be inferred to be Apple
from passing in the constant Apple
which matches the T.class
type restriction. T
is then a constant you can use with is_a?
.
Upvotes: 1
Reputation: 116880
As @ RX14 said, it looks like you want to check the run-time "type", i.e. .class
. Here's an example:
class Apple
@name = "Apple"
end
def check(obj : Object)
obj.class == Apple
end
a=Apple.new
p check(a)
Upvotes: 0
Reputation: 123
One solution I have is this for my function:
# Return the position of an object of class "something"
def self.where_is?(something)
@@grid.each do |position, thing|
return position if thing.is_a?(typeof(something))
end
end
And this for the test:
it "gives a random thing location" do
world = Map.new(4)
apple = Apple.new(Position.new(1, 2))
world.add_entity(apple)
position = Map.where_is?(Apple.new(Position.new(0, 0)))
position.should eq Position.new(1, 2)
end
I will use it like this if there is no other solution. But I would prefer to be able to search directly the class Apple
instead of creating an instance of Apple
I would like to be able to do position = Map.where_is?(Apple)
instead of
position = Map.where_is?(Apple.new(Position.new(0, 0)))
Upvotes: 1