Curly bracket constructors?
Asked Answered
C

2

5

While reading through the Crystal docs, I came across this line:

 deq = Deque{2, 3}

So I think this calls the Deque.new(array : Array(T)) constructor. However, I did not find any documentation about this syntax whatsoever. (EDIT: The documentation can be found here)

To test this way of calling constructors, I wrote the following test

class Foo(T)
  def initialize(@bar : Array(T)); end

  def to_s(io : IO)
    io << "Foo: "
    io << @bar
  end
end

puts Foo{1} # Line 10

But, compiling it prints this error:

Error in line 10: wrong number of arguments for 'Foo(Int32).new' (given 0, expected 1)
Overloads are:
 - Foo(T).new(bar : Array(T))

Which I really don't understand at all. Foo(Int32){1} Raises the same error.

Question is, what is this Klass{1, 2, 3} syntax? And how do you use it?

Canula answered 14/3, 2018 at 12:34 Comment(0)
S
9

They are documented here: https://crystal-lang.org/docs/syntax_and_semantics/literals/array.html


Array-like Type Literal

Crystal supports an additional literal for arrays and array-like types. It consists of the name of the type followed by a list of elements enclosed in curly braces ({}) and individual elements separated by a comma (,).

Array{1, 2, 3}

This literal can be used with any type as long as it has an argless constructor and responds to <<.

IO::Memory{1, 2, 3}
Set{1, 2, 3}

For a non-generic type like IO::Memory, this is equivalent to:

array_like = IO::Memory.new
array_like << 1
array_like << 2
array_like << 3

For a generic type like Set, the generic type T is inferred from the types of the elements in the same way as with the array literal. The above is equivalent to:

array_like = Set(typeof(1, 2, 3)).new
array_like << 1
array_like << 2
array_like << 3

The type arguments can be explicitly specified as part of the type name:

Set(Number) {1, 2, 3}
Seismo answered 14/3, 2018 at 12:58 Comment(0)
M
3

To create such a type you need to define an argless contructor and #<< method:

class Foo(T)
  def initialize
    @store = Array(T).new
  end

  def <<(elem : T)
    @store << elem
  end
end

foo = Foo(Int32){1, 2, 3}
p foo #=> #<Foo(Int32):0x103440b20 @store=[1, 2, 3]>
Melessa answered 14/3, 2018 at 13:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.