Crystal: restriction of abstract def return value, not works

Created on 15 Nov 2016  路  10Comments  路  Source: crystal-lang/crystal

this is compiled, but should not:

require "json"

abstract class A
  abstract def bla : String # <= expected to return string only

  def show
    p bla.to_json
  end
end

class B < A
  def bla
    1 # <= Int32
  end
end

B.new.show

in case when i change my api, but all code is compiled ok O_o, i want compiler to show this bugs

feature accepted compiler

Most helpful comment

@jgaskins Pretty sure it's just a warning atm. Try running it with --warnings all

All 10 comments

see also #160

Duplicate of #160

i not sure that this is #160, because this is about abstract defs(which is declare interfaces and restrictions), which compiler should checks to implement by it declaration.

OK, I'll reopen, but it's very similar

I recently was surprised by this myself.

After playing around a bit I'm starting to suspect that the return type on an abstract method has zero ramifications whatsoever. E.g.,

module Interface
  abstract def foo : Zork
end

struct A
  include Interface

  def foo
    3.14159
  end
end

struct B
  include Interface

  def foo
    "pi"
  end
end

struct C
  @x : Interface

  def initialize(@x : Interface)
  end

  def foo
    @x.foo
  end
end

a = A.new
c = C.new(a)
typeof(c.foo) # => (Float64 | String)

The nonexistence of the type Zork is irrelevant, the code compiles, and the type Zork appears to have no effect on any real return type. I.e., : Zork at the end of the abstract method declaration seems to be a fancy form of whitespace.

If that's the case, maybe it would make sense for now to just outlaw return types on abstract methods. At least then there is then no surprise factor: the compiler tells you that it won't enforce restrictions on the return type, so don't even bother trying. Allowing return types on abstract methods could be restored in the future if they ever become meaningful.

Great. I think this is a pretty easy change, and would be happy to give it a shot, unless someone else (@RX14 ?) already plans to.

Just ran into this, and it was confusing. I understand, and agree with, the arguments from #160, but I think in the case for abstract methods is a little different, because I would like to enforce a return type of my subclasses. I'm not a fan of disallowing return types on abstract methods, as it feels like just a temporary band-aid.

Looks like this bug may still be active. This compiles on v0.30.1:

record ProductRequest, id : Int32
record ProductResponse, product : Product
record Product, id : Int32, name : String

abstract struct CatalogService
  abstract def get_product(value : ProductRequest) : ProductResponse
end

struct CatalogHandler < CatalogService
  # This should not compile since it does not return a `ProductResponse`
  def get_product(request : ProductRequest)
    "lol"
  end
end

CatalogHandler.new.get_product(ProductRequest.new(id: 123))

In this example, CatalogHandler#get_product(ProductRequest) returns a string but the abstract method it's implementing specifies a return type of ProductResponse.

@jgaskins Pretty sure it's just a warning atm. Try running it with --warnings all

Ooh, okay. I didn't know warnings were opt-in. Thanks!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pbrusco picture pbrusco  路  3Comments

grosser picture grosser  路  3Comments

TechMagister picture TechMagister  路  3Comments

Papierkorb picture Papierkorb  路  3Comments

asterite picture asterite  路  3Comments