oprypin / crsfml

Crystal bindings to SFML multimedia/game library

Home Page:https://oprypin.github.io/crsfml

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

SF::View#dup broken

vypxl opened this issue · comments

Hi, it seems like SF::View#dup is broken, because it tries to call initialize of either SF::View or SF::View::Reference (which appears twice in src/graphics/obj.cr btw), both of which do not accept a SF::View instance as a single parameter.

I stumbled upon this while trying to replace views. I tried to temporarily save window.view, then replace it, render stuff, and then setting it back to the old view. But by then, the old view got modified somehow?! so I tried to dup it.

Hmm? Seems to work

require "crsfml"

a = SF::View.new
a.reset(SF.float_rect(100, 100, 400, 200))

b = a.dup
p! b.size # => SF::Vector2(Float32)(@x=400.0, @y=200.0)

I think it's SF::View::Reference#dup that is broken, yeah.

require "crsfml"

w = SF::RenderWindow.new

a = w.view
p! a.size # => SF::Vector2(Float32)(@x=1000.0, @y=1000.0)

b = a.dup
p! b.size # Error: wrong number of arguments for 'SF::View::Reference.new' (given 1, expected 2)

Somehow, SF::View#dup gets broken too, but only if it is a instance member or a class:

require "crsfml"

class Test
  @view : SF::View

  def initialize
    @view = SF::View.new
  end

  def try_dup
    @view.dup
  end
end

t = Test.new
p! t.try_dup # Error: wrong number of arguments for 'SF::View#initialize' (given 1, expected 2, 0) / In lib/crsfml/src/graphics/obj.cr:4463:27

Wow, now that could very well be a Crystal bug. Thanks, I'll check that separately, even though my fix would've gotten both.

So I reduced the sub-issue to this:

class Foo
  def initialize()
  end
  def initialize(copy : Foo)
  end
  def dup() : self
    return typeof(self).new(self)
  end
end

class Bar < Foo
  def initialize(x : Int32)
  end
end

class Test
  @foo : Foo = Foo.new

  def foo_dup
    @foo.dup
  end
end

Test.new.foo_dup
 7 | return typeof(self).new(self)
                         ^--
Error: wrong number of arguments for 'Foo#initialize' (given 1, expected 0)

And I concluded that this is not a bug. It happens due to Crystal's reduction of a type to the whole class hierarchy. I suppose these conditions cause typeof(self) to end up being "Foo or any subclass" rather than just "Foo". And then indeed you can't initialize "Foo or any subclass" with 1 arg because not all of them support initialization with 1 arg. So first off, I should've used self.class instead of typeof(self), but of course it's irrelevant anymore, because now I just use the explicit class name instead (see the fixing commit).

Certainly interesting

I think the fix actually introduced a new bug related to duplicating certain objects derived from abstract structs.

The following code leads to an error:

a = SF::Event::Resized.new
b = a.dup

Error: can't instantiate abstract struct SF::Event::SizeEvent

Admittedly, there are few scenarios in which you'd want to copy an event, but I stumbled upon this while trying to bind crSFML to Ruby using Anyolite. I can construct a workaround, but it still might be an issue unless this is intended in some way.