Hello, I have a question, I would like for all of my classes, pass all my arguments by Hash. But is it possible to initialize a single Hash property with differents types of possible value (I mean for example a hash, with some String value, Integer … etc)
For example, I would like to do something like that:
class Thing
property arguments : Hash
property id : Integer
property name : String
def initialize(@arguments)
end
end
var = Thing.new({id: 0, name: "Name"})
Technically speaking {id: 0, name: "Name"}
is a NamedTuple
not a Hash
. But in your case you could type the hash property as like Hash(String, String | Int32, Bool, ...)
but even that would be kinda meh as you’d prob run into type mismatches in some cases. Could also maybe use generics to handle it. E.g. Generics - Crystal.
Handling nested objects would also be challenging. Plus to set the actual ivars you’d need to do something like:
def iniitalize(arguments)
@id = arguments["id"].as Int32
@name = arguments["name"].as String
end
Could possibly use some macro to build that out for you automatically, but
.
It would be easier if you didn’t store the hash as its kinda pointless given you could just reconstruct the hash based on the other ivars.
What’s the use case for this? I would say its a bit of a smell, esp when you can just do Thing.new id: 0, name: "Name"
.
The thing is, I just would like to initialize the class members in the order I want. Something flexible
I’m not sure i follow. If you have a class like:
class Thing
property id : Int32
property name : String
def initialize(@id : Int32, @name : String); end
end
You can do both Thing.new id: 10, name: "foo"
or Thing.new name: "foo", id: 10
. I.e. it doesn’t matter which order you provide the required args when providing them as named arguments.
I didn’t knew that o-o
Why crystal compiler complain when I set the property id as Int64 ? When I initialize my instancied class, I have an error when I set for example the value to 1
Can you share an example of that? It seems to work work fine Carcin.
Sorry, I said a mistake, it’s the opposite:
class Thing
property id : Int64
def initialize(@id)
end
end
class NamedThing < Thing
property name : String
def initialize(@id,@name)
super(@id)
end
end
var = NamedThing.new name: "Truc", id: 0
puts var.name
Showing last frame. Use --error-trace for full trace.
In NamedThing.cr:7:20
7 | def initialize(@id,@name)
^--
Error: instance variable '@id' of Thing must be Int64, not Int32
The gist of it is you do not want to use @id
within NamedThing
, as its typing @id
as an Int32
(since there is no type restriction on it). Then when you do the super(@id)
it fails since the id
property of Thing
is typed as Int64
which fails since you’re passing up an Int32
.
I.e. you prob want to do like:
def initialize(id,@name)
super id
end
1 Like
super id
is definitely the way to go, but if you run into this in the future in a situation where super
doesn’t make sense (like below), then you can also fix it by specifying the method argument type restriction:
Before
class Thing
property id : Int64
def initialize(@id)
end
end
var = Thing.new 0 # => Error: instance variable '@id' of Thing must be Int64, not Int32
puts var.id
After
class Thing
property id : Int64
def initialize(@id : Int64) # <--- Add a type restriction
end
end
var = Thing.new 0
puts var.id # => 0
The reason is that the compiler doesn’t know to automatically cast your Int32
literal (0
) into an Int64
unless there’s a type restriction.
Edit:
Actually, even with super
, you still need the type restriction. Try this:
class Thing
property id : Int64
def initialize(@id : Int64)
end
end
class NamedThing < Thing
property name : String
def initialize(id, @name)
super id
end
end
var = NamedThing.new name: "Truc", id: 0
puts var.name # => Truc
I have again an error T_T
class Thing
property id : Int64
def initialize(@id : Int64)
end
end
class NamedThing < Thing
property name : String
def initialize(id,@name)
super id
end
end
var = NamedThing.new name: "Truc", id: 0
puts var.name
Log:
Showing last frame. Use --error-trace for full trace.
In NamedThing.cr:8:9
8 | super id
^----
Error: no overload matches 'Thing#initialize' with type Int32
Overloads are:
- Thing#initialize(id : Int64)
What version of Crystal are you using? That exact code works on carc.in with Crystal 1.3.2.
I’m on Gentoo, I have the 1.2.2 version
In that case you’ll need to do one of the following:
- Upgrade to
1.3.x
- Pass in an
Int64
, like 0_i64
- Convert the
Int32
to a Int64
, like super id.to_i64
- Give a property type restriction to
id
within NamedThing
, like def initialize(id : Int64, @name)
1 Like