This (SDL client) code will not compile. How to fix it?
# app.cr
class ColorPicker
property color : UInt32
def initialize(@color)
end
end
picker = ColorPicker.new(0xFF0000FF)
enum UserEventType
COLOR_PICKED
DRAWING_CREATED
end
event = LibSDL::UserEvent.new(
type: user_event_type,
code: UserEventType::COLOR_PICKED,
data1: pointerof(picker.color),
data2: nil)
LibSDL.push_event(pointerof(event))
$ crystal app.cr
# In app.cr
# data1: pointerof(picker.color),
# Error: can't take address of picker.color
# LibSDL.push_event(pointerof(event))
# Error: argument 'event' of 'LibSDL#push_event' must be Pointer(LibSDL::Event), not Pointer(LibSDL::UserEvent)
Also, picker.color is a call, so it doesn’t have anything a pointer could point at. pointerof only works with variables.
You might want to take the pointer of the instance variable @color: pointerof(picker.@color).
EDIT:
My goal was to obtain a pointer to the color UInt32 variable of the picker instance (expressed in C with &picker.x). I forgot that – correct me if I’m wrong – crystal struct and class instance vars are not accessible other than by methods. In that context, pointer_of(picker.color) doesn’t make any sense. What could be improved, if anything, would be the compilation error message. Something in the order of can't take address of method picker.color would have helped.
Also, placing the search box at the head of the topics list and filtering the latter by matching search results sections might help flatten the curve a bit. So much more about pointers exists than is found in the one pointer_of section of the topics list.
IGNORE:
I assumed that the return type of picker.color (indirectly created after declaring color a property) would be taken into account by the compiler, as opposed to compilation failing with a not-so-helpful can't take address of picker.color message. That left me on a chase before I saw your helpful answer.
This looks a bit odd. picker is already a pointer (because ColorPicker is a class, i.e. a reference type). Do you really want a double pointer here? This is now a pointer to the pointer of an instance of ColorPicker.
Maybe this should rather be pointer.as(Void*)?
In the code below, both typeof(a.age) and typeof(pointerof(a.@age)) return UInt8 where typeof(pointerof(a.age)) fails.
Given a message of pointerof expects a variable or constant., I (newcomer) would check typeof(a.age) and, given a return value of UInt8, would still wonder why pointerof had failed.
Is there documentation on how compilation checks are done? Reading up on this would help me.
class Aged
property age : UInt8 = 0
def initialize(@age)
end
def age()
@age
end
end
a = Aged.new(42)
puts "a = Aged.new(42)"
puts typeof(a) # Aged
puts typeof(a.@age) # UInt8
puts typeof(a.age) # UInt8
puts typeof(pointerof(a)) # Pointer(Aged)
puts typeof(pointerof(a.@age)) # Pointer(UInt8)
# puts typeof(pointerof(a.age)) # Error: can't take address of a.age
age_ptr = pointerof(a.@age)
puts typeof(age_ptr) # Pointer(UInt8)
I don’t understand this part. Which documentation page are you referring to?
Not really. This happens all over the place in the compiler codebase. Whenever the compiler notices something is wrong while compiling the program, it errors.
The compiler code is all Crystal and relatively approachable (not in its entire complexity, but individual aspects are quite readable). If you grep for the error message, it’ll take you to crystal/src/compiler/crystal/semantic/main_visitor.cr at 96bf61e053eeb38036b8369e5ae030ec614fdc96 · crystal-lang/crystal · GitHub
I believe this example is quite clear, even without prior experience with the compiler: the visit(PointerOf) method calls pointerof_var which figures out whether a pointer can be taken, based on the type of the expression.
Incidentally, I had googled “Crystal SDL User event” a few days ago and both the original, not so helpful, answers provided by Leo (Brave browser) and Gemini (Chrome browser) AI assistants were automatically updated (tabs had remained open) this morning to show my (also in need of improvement) initial code.
Will post improved, final code here, for clarity’s sake.
# app.cr
enum UserEventCode
DRAWING_CREATED
COLOR_PICKED
end
class ColorPicker
property color : UInt32
def initialize(@color)
end
end
picker = ColorPicker.new(0xFF0000FF)
user_event_type : UInt32 = LibSDL.register_events(1)
event = LibSDL::UserEvent.new(
type: user_event_type,
code: UserEventCode::COLOR_PICKED,
data1: picker.as(Void*),
data2: nil)
LibSDL.push_event(pointerof(event))