struct Proc(*T, R)
Overview
AProc represents a function pointerwith an optional context (the closure data).
It is typically createdwith a proc literal:
# A proc without arguments
-> { 1 } # Proc(Int32)
# A proc with one argument
->(x : Int32) { x.to_s } # Proc(Int32, String)
# A proc with two arguments:
->(x : Int32, y : Int32) { x + y } # Proc(Int32, Int32, Int32)
SeeProc literals in the language reference.
The types of the arguments (T) are mandatory, exceptwhen directly
sending a proc literal to a lib fun in C bindings.
The return type (R) is inferred from the proc's body.
A special new method is provided too:
Proc(Int32, String).new { |x| x.to_s } # Proc(Int32, String)
This form allows you to specify the return type and to check it against the proc's body.
Anotherway to create aProc is by capturing a block:
def capture(&block : Int32 -> Int32)
# block argument is used, so block is turned into a Proc
block
end
proc = capture { |x| x + 1 } # Proc(Int32, Int32)
proc.call(1) # => 2
When capturing blocks, the type of the arguments and return type must be specified in the capturing method block signature.
Passing a Proc to a C function
Passing aProc to a C function, for example as a callback, is possible
as long as theProc isn't a closure. If it is, either a compile-time or
runtime errorwill happen depending onwhether the compiler can check this.
The reason is that aProc is internally represented as two void pointers,
one having the function pointer and another the closure data. If just
the function pointer is passed, the closure datawill be missing at invocation time.
Most of the time a C function that allows setting a callback also provide an argument for custom data. This custom data is then sent as an argument to the callback. For example, suppose a C function that invokes a callback at every tick, passing that tick:
lib LibTicker
fun on_tick(callback : (Int32, Void* ->), data : Void*)
end
To properly define awrapper for this functionwe must send theProc as the
callback data, and then convert that callback data to theProc and finally invoke it.
module Ticker
# The callback for the user doesn't have a Void*
@@box = Pointer(Void).null
def self.on_tick(&callback : Int32 ->)
# Since Proc is a {Void*, Void*}, we can't turn that into a Void*, so we
# "box" it: we allocate memory and store the Proc there
boxed_data = Box.box(callback)
# We must save this in Crystal-land so the GC doesn't collect it (*)
@@box = boxed_data
# We pass a callback that doesn't form a closure, and pass the boxed_data as
# the callback data
LibTicker.on_tick(->(tick, data) {
# Now we turn data back into the Proc, using Box.unbox
data_as_callback = Box(typeof(callback)).unbox(data)
# And finally invoke the user's callback
data_as_callback.call(tick)
}, boxed_data)
end
end
Ticker.on_tick do |tick|
puts tick
end
Note thatwe save the box in@@box. The reason is that ifwe don't do it,
and our code doesn't reference it anymore, the GCwill collect it.
The C librarywill of course store the callback, but Crystal's GC has
noway of knowing that.
Defined in:
primitives.crproc.cr
Constructors
- .new(pointer : Pointer(Void), closure_data : Pointer(Void)) : self
-
.new(&block : self)
Creates a
Procby capturing the givenblock.
Instance Method Summary
- #==(other : self)
- #===(other : self)
-
#===(other)
Case equality.
-
#[](*args : *T) : R
Invokes this
Procand returns the result. -
#arity
Returns the number of arguments of this
Proc. -
#call(*args : *T) : R
Invokes this
Procand returns the result. - #clone
- #closure? : Bool
- #closure_data : Pointer(Void)
- #hash(hasher)
-
#partial(*args : *U) forall U
Returns a new
Procthat has its first arguments fixed to the values given byargs. - #pointer : Pointer(Void)
-
#to_s(io : IO) : Nil
Prints a nicely readable and concise string representation of this object, typically intended for users, toio.
Instance methods inherited from struct Value
==(other : Log::Metadata::Value)==(other : JSON::Any)
==(other : YAML::Any)
==(other) ==, dup dup
Instance methods inherited from class Object
! : Bool
!,
!=(other)
!=,
!~(other)
!~,
==(other)
==,
===(other : JSON::Any)===(other : YAML::Any)
===(other) ===, =~(other) =~, as(type : Class) as, as?(type : Class) as?, class class, dup dup, hash(hasher)
hash hash, in?(collection : Object) : Bool
in?(*values : Object) : Bool in?, inspect(io : IO) : Nil
inspect : String inspect, is_a?(type : Class) : Bool is_a?, itself itself, nil? : Bool nil?, not_nil!(message)
not_nil! not_nil!, pretty_inspect(width = 79, newline = "\n", indent = 0) : String pretty_inspect, pretty_print(pp : PrettyPrint) : Nil pretty_print, responds_to?(name : Symbol) : Bool responds_to?, tap(&) tap, to_json(io : IO) : Nil
to_json : String to_json, to_pretty_json(indent : String = " ") : String
to_pretty_json(io : IO, indent : String = " ") : Nil to_pretty_json, to_s(io : IO) : Nil
to_s : String to_s, to_yaml(io : IO) : Nil
to_yaml : String to_yaml, try(&) try, unsafe_as(type : T.class) forall T unsafe_as
Class methods inherited from class Object
from_json(string_or_io : String | IO, root : String)from_json(string_or_io : String | IO) from_json, from_yaml(string_or_io : String | IO) from_yaml
Macros inherited from class Object
class_getter(*names, &block)
class_getter,
class_getter!(*names)
class_getter!,
class_getter?(*names, &block)
class_getter?,
class_property(*names, &block)
class_property,
class_property!(*names)
class_property!,
class_property?(*names, &block)
class_property?,
class_setter(*names)
class_setter,
def_clone
def_clone,
def_equals(*fields)
def_equals,
def_equals_and_hash(*fields)
def_equals_and_hash,
def_hash(*fields)
def_hash,
delegate(*methods, to object)
delegate,
forward_missing_to(delegate)
forward_missing_to,
getter(*names, &block)
getter,
getter!(*names)
getter!,
getter?(*names, &block)
getter?,
property(*names, &block)
property,
property!(*names)
property!,
property?(*names, &block)
property?,
setter(*names)
setter
Constructor Detail
Creates aProc by capturing the givenblock.
The block argument types are inferred from theProc's type arguments. The
return type of the block must match the return type specified in theProc
type.
gt = Proc(Int32, Int32, Bool).new do |x, y|
x > y
end
gt.call(3, 1) # => true
gt.call(1, 2) # => false
Instance Method Detail
Case equality.
The#=== method is used in acase ... when ... end expression.
For example, this code:
case value
when x
# something when x
when y
# something when y
end
Is equivalent to this code:
if x === value
# something when x
elsif y === value
# something when y
end
Object simply implements#=== by invoking#==, but subclasses
(notablyRegex) can override it to provide meaningful case-equality semantics.
Invokes thisProc and returns the result.
add = ->(x : Int32, y : Int32) { x + y }
add[1, 2] # => 3
Same as#call.
Returns the number of arguments of thisProc.
add = ->(x : Int32, y : Int32) { x + y }
add.arity # => 2
neg = ->(x : Int32) { -x }
neg.arity # => 1
Invokes thisProc and returns the result.
add = ->(x : Int32, y : Int32) { x + y }
add.call(1, 2) # => 3
Returns a newProc that has its first arguments fixed to
the values given byargs.
SeeWikipedia, Partial application
add = ->(x : Int32, y : Int32) { x + y }
add.call(1, 2) # => 3
add_one = add.partial(1)
add_one.call(2) # => 3
add_one.call(10) # => 11
add_one_and_two = add_one.partial(2)
add_one_and_two.call # => 3
Prints a nicely readable and concise string representation of this object, typically intended for users, toio.
This method is calledwhen an object is interpolated in a string literal:
"foo #{bar} baz" # calls bar.to_io with the builder for this string
IO#<< calls this method to append an object to itself:
io << bar # calls bar.to_s(io)
Thus implementations must not interpolateself in a string literal or call
io << selfwhich bothwould lead to an endless loop.
Also see#inspect(IO).