Crystal: Comparing union of sub-structs affects comparison of other structs

Created on 27 Sep 2017  路  5Comments  路  Source: crystal-lang/crystal

abstract struct A; end
struct B < A; end
struct C < A; end

(B.new || C.new) == B.new

p C.new == C.new #=> false
abstract struct A; end
struct B < A; end
struct C < A; end

B.new

p C.new == C.new #=> true

Crystal 0.23.1 (2017-09-08) LLVM 4.0.1
OS X 10.11.6 (15G1611)

bug compiler topicsemantic

Most helpful comment

Suggested title:

Comparing union of sub-structs affects comparison of other structs

Reduced:

abstract struct A; end
struct B < A; end
struct C < A; end

(B.new || C.new) == B.new

p C.new == C.new
[`false`](https://carc.in/#/r/2t3t)
abstract struct A; end
struct B < A; end
struct C < A; end

B.new

p C.new == C.new
[`true`](https://carc.in/#/r/2t3u)

All 5 comments

Suggested title:

Comparing union of sub-structs affects comparison of other structs

Reduced:

abstract struct A; end
struct B < A; end
struct C < A; end

(B.new || C.new) == B.new

p C.new == C.new
[`false`](https://carc.in/#/r/2t3t)
abstract struct A; end
struct B < A; end
struct C < A; end

B.new

p C.new == C.new
[`true`](https://carc.in/#/r/2t3u)

@oprypin thanks!

"Reduced" a bit more:

struct Value
  def foo(other)
    "BAD"
  end
end

struct Struct
  def foo(other : self)
    {{@type}}
    "GOOD"
  end
end

abstract struct A
end

struct B < A
end

struct C < A
end

p (B.new || C.new).foo(C.new) # => "BAD"

It seems a macro def with self restriction isn't matched here for some reason.

Not sure if this is the same problem. I tried to implement singleton and encounter the following error

abstract class A(T); end
class C < A(Int32); end

class B < A(Nil)
  @@instance = uninitialized B

  def self.new
    @@instance ||= B.allocate.tap(&.initialize)
  end
end
(B.new || C.new) == B.new
puts B.new == B.new

Fails with error

>crystal spec/test.cr
Invalid memory access (signal 11) at address 0x0
[0x10773ddeb] *CallStack::print_backtrace:Int32 +107
[0x1077297cc] __crystal_sigfault_handler +60
[0x7fff8d3c152a] _sigtramp +26
[0x10771956f] __crystal_main +1279
[0x1077296c8] main +40

but this works as expected:

C.new
puts B.new == B.new #=> true

by the way I managed to implement singleton this way:

class B < A(String)
  @@instance : Nil | B
  @@instance = nil

  def self.new
    @@instance ||= B.allocate.tap(&.initialize)
    @@instance.as(B)
  end
end

(B.new || C.new) == B.new
puts B.new == B.new #=> true
Was this page helpful?
0 / 5 - 0 ratings

Related issues

ezrast picture ezrast  路  84Comments

asterite picture asterite  路  70Comments

akzhan picture akzhan  路  67Comments

HCLarsen picture HCLarsen  路  162Comments

straight-shoota picture straight-shoota  路  91Comments