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 !
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?.
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)))
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)
Related
I want to load a property on demand but i cant get it working.
I have a class with a transient property foo. So the property is not stored when the object is saved. When I use a method that is calling the property 'foo', I want that the value of foo is loaded from a separate mat file and stored into the object as long as it is in workspace.
I tried something with get and set methods but cant get it working. Is this possible? Or do I always add a line of code that is loading the property? The following code does not do what I want but it gives an indication what i tried.
In addition, the code below keeps loading the foo.mat file when the property is used. I want to load foo.mat only one time and store it as a property and retrieve the data from there instead of loading. The reason for my question is that the foo property is rather large i.e. a class with many properties in itself. I only want to load it when it is needed and dont want to store it in foobar class itself.
classdef foobar
properties(Transient = true)
foo
end
methods
function value = get.foo(obj)
if isempty(obj.foo)
value = load('foo.mat');
disp('load foo.mat');
end
end
function obj = set.foo(obj,value)
obj.foo = value;
end
end
end
You have two major problems here:
In your get.foo method, once you load the value, you never update the value of foo in the object, so it remains empty.
Even if you tried to update foo in your get.foo method, it would still be empty in the original object because your foobar class is a value class. Methods that modify a value class object have to return the modified object as an output, because they are essentially modifying a copy of the object. A set method of a value class returns a modified object that is used to overwrite the original object, but get methods don't return modified objects (since they aren't generally expected to modify them). To get around that limitation, you'll need the reference-like behavior of a handle class (here's a related question you may want to take a look at for more background).
So, in order to get the behavior you want you'd have to implement foobar as a subclass of the handle class and update the foo field when you first load it:
classdef foobar < handle % Inherit from handle class
properties(Transient = true)
foo
end
methods
function value = get.foo(obj)
if isempty(obj.foo)
value = load('foo.mat');
disp('load foo.mat');
obj.foo = value; % Update foo
end
value = obj.foo; % Return current foo value
end
function set.foo(obj, value) % Return value is unnecessary for handle class
obj.foo = value;
end
end
end
This should now give you the behavior you want (i.e. foo is only loaded when it is first accessed).
Note: Any method that invokes get.foo will initialize foo. One method you may overlook, because it's created by default for a class, is the disp method. The default display for a class object will show the class name followed by a list of non-hidden public properties and their values. Note what happens when I create an object of class foobar from above with and without a semicolon:
>> f = foobar; % Display is suppressed
>> f = foobar
f =
load foo.mat % foo gets initialized...
foobar with properties:
foo: [1×1 struct] % ...because its value is displayed here
If you want to avoid this, you can overload the disp function for your foobar object so that displaying the object doesn't access (and thus initialize) foo. For example, you can add this method to the above foobar class:
function disp(obj)
disp(' foobar object');
end
Now you won't initialize foo when displaying the object:
>> f = foobar
f =
foobar object % foo not yet initialized
>> a = f.foo;
load foo.mat % foo initialized because we accessed it
EDIT I have found a much easier way to do this in lua but the problem is method inheritance
basically the syntax would go like this
Object
object = {}
object.base = ?
object.value = 0
function object:create(x, y)
local copy
--copy table
if type(self) == "table" then
copy = {} for k, v in pairs(self) do copy[k] = v:create() end
else
copy = self
end
--set base
copy.base = self
--set copy vars
copy.x = x
copy.y = y
return copy
end
function object:update()
self.value = self.value + 1
end
Player
player = object:create()
player.value = 1
function player:create(x, y, size)
base:create(x, y) --inherit base event
end
--automaticly inherits update event since it is not redeclared
I'm not sure how to go about doing this though
Inheritance in Lua is basically implemented using metatables. In code:
function object:new (o)
o = o or {}
-- Put the rest of your create function code here
setmetatable(o, self)
self.__index = self
return o
end
function object:update()
self.value = self.value + 1
end
Now create an empty Player class that will be a subclass of your base Object class and will inherit all its behavior from it.
Player = Object:new()
Player is now an instance of Object. Instantiate a new Player object, p in order to inherit the new method from Object.
p = Player:new{x=1, y=2, size=3}
This time, however, when new executes, the self parameter will refer to player. Therefore, the metatable of p will be Player, whose value at index __index is also Player. So, p inherits from Player, which inherits from Object.
Now when you'll code:
p:create{x=10, y=20, size=100}
lua won't find a create field in p, so it will look into Player class; it won't find a create field there, too, so it will look into Object and there it will finds the original implementation of create. The same thing will happen with the update function.
Of course Player class can redefine any method inherited from its superclass, Object. So for example you can redefine -if you want- the create function:
function Player:create()
--New create code for Player
end
Now when you'll call p:create{x=10, y=20, size=190}, Lua will not access the Object class, because it finds the new create function in Player first.
You are making a reference to base directly, whereas, it is actually an attribute of your player object:
function player:create(x, y, size)
self.base:create(x, y)
end
Given a table, is there a way to check if it is an instance object of any class?
Assume all class definition looks like:
Class = {}
Class.__index = Class
function Class.new()
return setmetatable({}, Class) -- returns an instance
end
I use just getmetatable function
if getmetatable(thing) == Class then
But if you use some type of inheritence then you can try this one
local A = {} A.__index = A
function A:new() return setmetatable({}, A) end
function A:foo() print('foo') end
local B = setmetatable({}, A) B.__index = B
function B:new() return setmetatable({}, B) end
function B:boo() print("boo") end
local function is_instance(o, class)
while o do
o = getmetatable(o)
if class == o then return true end
end
return false
end
local a = A:new()
local b = B:new()
a:foo()
b:foo()
b:boo()
print(is_instance(a, A))
print(is_instance(a, B))
print(is_instance(b, B))
print(is_instance(b, A))
In theory you could read table's metatable with getmetatable(), and compare received table agains list of classes known to you.
But it means metatable shouldn't be protected (__metatable field is not set to something different, getmetatable() is not removed within sandbox, etc), and you should know all available classes.
If there some metatable set on a table, it doesn't mean that table is a part of class hierarchy, or class at all. It just might use metatables to solve its own tasks.
I have a Report class that several models inherit from (OverviewReport, CategoryReport, etc...). Each of these inherited classes has specific methods/attributes that need to be customized for that type of report.
The desired report type is passed in via the params hash, so I can do something like the following:
# reports_controller.rb
def index
case params[:type]
when "overview" then OverviewReport.new(...)
when "category" then CategoryReport.new(...)
...etc...
end
end
This works, but I would like to clean up the controller a little bit. I would like to be able to do this:
# reports_controller.rb
def index
#report = Report.new(params[:type], ...)
end
# report.rb class
def initialize(type, options)
case type
when "overview" then self = OverviewReport.new(type, options)
when "category" then self = CategoryReport.new(type, options)
end
end
However, you can't change the value of self, so how would you go about accomplishing this functionality?
The intent is the clean up the controller code and abstract away which report you're using, so I can call #report.some_method() and it will call the inherited-specific method.
Is there a clean solution to this, or am I stuck with a (somewhat) lengthy case statement in my controller?
One solution would be to use a "factory" class whose sole purpose is to instantiate the correct class:
# reports_controller.rb
def index
#report = AgnosticReport.new(type)
end
# agnostic_report.rb
def initialize(type)
case type
when "overview" then return OverviewReport.new(type)
when "category" then return CategoryReport.new(type)
...etc...
end
end
This is perfectly acceptable, but I was wondering if there was any need to add a "third" layer of classes to this situation.
Do you have the ability to change the type params passed?
If so I would use constantize
params[:type] being "Overview Report" or "Category Report" e.t.c.
then use
#report = params[:type].constantize.new
s = "OverviewReport",
s.constantize => OverviewReport
I wanna declare a record inside a class as follows:
class player (x, y)=
object(self)
type gun = {x:int; y:int; active:bool}
val guns = Array.create 5 {x=0; y=0; active=false}
....
but the compiler claim that this line is syntax error : type gun = {x:in ....
when declared outside the class like this
type : gun = {x:int; y:int; active:bool}
class player (x, y)=
object(self)
val guns = Array.create 5 {x=0; y=0; active=false}
....
the error is : unbound value gun.
so anyone know how to reach the same functionality with another way?
thank you!
********* solved***
Bizare now it's working when the type is declared outside, thank you
Why don't you define the type gun outside of the class definition?