Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions spec/std/indexable_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ private class SafeIndexable
def initialize(@size : Int32, @offset = 0_i32)
end

def unsafe_fetch(i)
def unsafe_fetch(i) : Int32
raise IndexError.new unless 0 <= i < size
i + @offset
(i + @offset).to_i
end
end

Expand All @@ -22,7 +22,7 @@ private class SafeStringIndexable
def initialize(@size : Int32)
end

def unsafe_fetch(i)
def unsafe_fetch(i) : String
raise IndexError.new unless 0 <= i < size
i.to_s
end
Expand All @@ -36,7 +36,7 @@ private class SafeMixedIndexable
def initialize(@size : Int32)
end

def unsafe_fetch(i)
def unsafe_fetch(i) : String | Int32
raise IndexError.new unless 0 <= i < size
i.to_s
end
Expand All @@ -50,7 +50,7 @@ private class SafeRecursiveIndexable
def initialize(@size : Int32)
end

def unsafe_fetch(i)
def unsafe_fetch(i) : SafeRecursiveIndexable | Int32
raise IndexError.new unless 0 <= i < size
if (i % 2) == 0
SafeRecursiveIndexable.new(i)
Expand Down
20 changes: 10 additions & 10 deletions src/array.cr
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ class Array(T)
# ary[0][0] = 2
# ary # => [[2], [1], [1]]
# ```
def self.new(size : Int, &block : Int32 -> T)
def self.new(size : Int, & : Int32 -> T)
Array(T).build(size) do |buffer|
size.to_i.times do |i|
buffer[i] = yield i
Expand All @@ -173,7 +173,7 @@ class Array(T)
# LibSome.fill_buffer_and_return_number_of_elements_filled(buffer)
# end
# ```
def self.build(capacity : Int) : self
def self.build(capacity : Int, & : Pointer(T) ->) : self
ary = Array(T).new(capacity)
ary.size = (yield ary.to_unsafe).to_i
ary
Expand Down Expand Up @@ -1048,7 +1048,7 @@ class Array(T)
end

# Optimized version of `Enumerable#map`.
def map(&block : T -> U) forall U
def map(& : T -> U) forall U
Array(U).new(size) { |i| yield @buffer[i] }
end

Expand All @@ -1062,7 +1062,7 @@ class Array(T)
# ```
#
# See also: `Array#select`.
def select!
def select!(& : T ->) : self
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def select!(& : T ->) : self
def select!(& : T -> Bool) : self

Is there a reason this and like reject(!) shouldn't be forced to return a Bool?

Copy link
Copy Markdown
Member Author

@straight-shoota straight-shoota Mar 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would definitely be a breaking change (so should be brought up in a different issue). Right now, the value just needs to be interpreted as truthy. And I think that's probably good. No need to force users to a bool conversion.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't T -> mean Nil return value type?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope. It means there's no restriction on the return type. Basically like a free var.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think @Sija is right. You need to use underscore to mean any type

Copy link
Copy Markdown
Member

@Blacksmoke16 Blacksmoke16 Mar 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's equivalent to T -> _, which means "allow any return type".

EDIT: Oops, didn't refresh 😬.

Copy link
Copy Markdown
Member Author

@straight-shoota straight-shoota Mar 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it's different for captured blocks.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally we should probably improve the semantics, maybe make empty invalid for non-captured blocks and require an underscore since that's more explicit and fits with the use of underscore in the type grammar.

But for now, it's better to use empty because it's not entirely equivalent to underscore: https://forum.crystal-lang.org/t/difference-between-underscore-and-empty-as-block-return-value/2998

Copy link
Copy Markdown
Member Author

@straight-shoota straight-shoota Jul 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #10932 for the underscore issue and #10931 for a discussion about the intended semantics.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on #11210 we never constrain the return type to Bool in contexts like this.

reject! { |elem| !yield(elem) }
end

Expand Down Expand Up @@ -1090,7 +1090,7 @@ class Array(T)
# ```
#
# See also: `Array#reject`.
def reject!
def reject!(& : T ->) : self
internal_delete { |e| yield e }
self
end
Expand Down Expand Up @@ -1151,7 +1151,7 @@ class Array(T)
# results = gems.map_with_index { |gem, i| "#{i}: #{gem}" }
# results # => ["0: crystal", "1: pearl", "2: diamond"]
# ```
def map_with_index(offset = 0, &block : T, Int32 -> U) forall U
def map_with_index(offset = 0, & : T, Int32 -> U) forall U
Array(U).new(size) { |i| yield @buffer[i], offset + i }
end

Expand Down Expand Up @@ -1350,7 +1350,7 @@ class Array(T)
result
end

def product(enumerable : Enumerable, &block)
def product(enumerable : Enumerable(U), & : T, U ->) forall U
self.each { |a| enumerable.each { |b| yield a, b } }
end

Expand Down Expand Up @@ -1874,7 +1874,7 @@ class Array(T)
# a.uniq { |s| s[0] } # => [{"student", "sam"}, {"teacher", "matz"}]
# a # => [{"student", "sam"}, {"student", "george"}, {"teacher", "matz"}]
# ```
def uniq(&block : T -> _)
def uniq(& : T ->)
if size <= 1
dup
else
Expand Down Expand Up @@ -1915,7 +1915,7 @@ class Array(T)
# a.uniq! { |s| s[0] } # => [{"student", "sam"}, {"teacher", "matz"}]
# a # => [{"student", "sam"}, {"teacher", "matz"}]
# ```
def uniq!
def uniq!(& : T ->) : self
if size <= 1
return self
end
Expand Down Expand Up @@ -2150,7 +2150,7 @@ class Array(T)
to_lookup_hash { |elem| elem }
end

protected def to_lookup_hash(&block : T -> U) forall U
protected def to_lookup_hash(& : T -> U) forall U
each_with_object(Hash(U, T).new) do |o, h|
key = yield o
unless h.has_key?(key)
Expand Down
8 changes: 4 additions & 4 deletions src/deque.cr
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class Deque(T)
# ```
# Deque.new(3) { |i| (i + 1) ** 2 } # => Deque{1, 4, 9}
# ```
def self.new(size : Int, &block : Int32 -> T)
def self.new(size : Int, & : Int32 -> T)
if size < 0
raise ArgumentError.new("Negative deque size: #{size}")
end
Expand Down Expand Up @@ -207,7 +207,7 @@ class Deque(T)
# ```
#
# See also: `Deque#select`.
def select!
def select!(& : T ->) : self
reject! { |elem| !yield(elem) }
end

Expand Down Expand Up @@ -235,7 +235,7 @@ class Deque(T)
# ```
#
# See also: `Deque#reject`.
def reject!
def reject!(& : T ->) : self
internal_delete { |e| yield e }
self
end
Expand Down Expand Up @@ -338,7 +338,7 @@ class Deque(T)
# Yields each item in this deque, from first to last.
#
# Do not modify the deque while using this variant of `each`!
def each : Nil
def each(& : T ->) : Nil
halfs do |r|
r.each do |i|
yield @buffer[i]
Expand Down
4 changes: 2 additions & 2 deletions src/enum.cr
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ struct Enum
# # yield IOMode::Async, 3
# end
# ```
def each
def each(& : self ->)
{% if @type.annotation(Flags) %}
return if value == 0
{% for member in @type.constants %}
Expand Down Expand Up @@ -468,7 +468,7 @@ struct Enum
# # yield IOMode::Async, 3
# end
# ```
def self.each
def self.each(& : self ->)
{% for member in @type.constants %}
{% unless @type.annotation(Flags) && %w(none all).includes?(member.stringify.downcase) %}
yield new({{@type.constant(member)}}), {{@type.constant(member)}}
Expand Down
Loading