Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type restriction should upcast #2729

Closed
chenkovsky opened this issue Jun 3, 2016 · 10 comments
Closed

Type restriction should upcast #2729

chenkovsky opened this issue Jun 3, 2016 · 10 comments

Comments

@chenkovsky
Copy link

chenkovsky commented Jun 3, 2016

example

class A
end

class B < A
  getter :v

  def initialize(@v : A)
  end
end

class C < A
  getter :v

  def initialize(@v : A)
  end
end

def foo(x : A)
  arr = [x]
 #if replace it with arr = [x.as(A)], it compiles.
  while arr.size > 0
    a = arr.pop
    case a
    when B
      arr << a.v
    when C
      arr << a.v
    end
  end
end
a = A.new
b = B.new a
c = C.new b
foo(c)

no overload matches 'Array(C)#<<' with type A+
Overloads are:

  • Array(T)#<<(value : T)
    Couldn't find overloads for these types:
  • Array(C)#<<(value : A)
@jhass
Copy link
Member

jhass commented Jun 3, 2016

smaller example https://carc.in/#/r/10la

class A
end

class B < A
end

def foo(a : A)
  p typeof(a)
end

foo B.new # => B, expected A

@jhass jhass added kind:bug A bug in the code. Does not apply to documentation, specs, etc. topic:compiler labels Jun 3, 2016
@jhass jhass changed the title array type inference error Type restriction should upcast Jun 3, 2016
@fernandes
Copy link
Contributor

@jhass the right behavior should be return A and if you want to access something particular to B, should call inside an if is_a?(B), right?

@jhass
Copy link
Member

jhass commented Jun 3, 2016

I would say so, yes.

@bcardiff
Copy link
Member

bcardiff commented Jun 3, 2016

Crystal only uses the type restriction in methods to choose. It does not restrict or use the type information during body method.

For example the following compiles and runs:

https://play.crystal-lang.org/#/r/10nc

def change(a : Enumerable)
  a[0] = 3
end

b = [1,2,3]
pp b # => b = [1, 2, 3]
change b
pp b # => b = [3, 2, 3]

The motivation is that it is the nearest behavior to an unrestricted method:

def change(a)
  a[0] = 3
end

I did raise this to @asterite in the past and what I exhibit here is more or less the sample he use to explain why he thinks it should work as it is.

And we can't solve the issue @chenkovsky / @jhass shows without loosing the working samples posted in this comment.

@jhass
Copy link
Member

jhass commented Jun 3, 2016

I guess I simply disagree that they should work and that they do work is expected.

@asterite
Copy link
Member

asterite commented Jun 3, 2016

Also:

def foo(x : Int)
  # I don't want x to be of type Int, just restrict it's type
  y = x.to_i32
end

And many, many more cases like that. That's why they are called "type restrictions" and not just "argument types". I'd leave this as an RFC or close it. It's a fundamental part of the language that, if changed, will break everything. So it basically needs to be reconsidered once the language evolves a bit more.

@jhass jhass added RFC status:draft and removed kind:bug A bug in the code. Does not apply to documentation, specs, etc. labels Jun 3, 2016
@jhass
Copy link
Member

jhass commented Jun 3, 2016

That makes the initial issue a duplicate of #1297 I guess.

@bcardiff
Copy link
Member

bcardiff commented Jun 3, 2016

@jhass I still have mixed feelings too :-). The surprise factor is as your minimal example, that the static typeof of the argument does not match the type restriction.

It feels too different from what it is used, even not formal, but is because we are narrow to the classic formalism or way to read the functions declarations.

I don't see it a duplicate of #1297. There, the question is how generic arguments should participate in the type restrictions or eventually in #is_a?, etc.

@ozra
Copy link
Contributor

ozra commented Jun 5, 2016

Personally I like the current concept of restriction.

Maybe it should be more clearly explained in docs, with increased clearer knowledge among crystal users (many probably assume semantics from syntactic similarity to other typed languages), and then perhaps some one comes up with a better/refined idea, otherwise I think it's neat.

@asterite
Copy link
Member

I'm closing this. A type restriction is just that: a restriction. The examples for Enumerable and Int are good enough for not considering doing this. You wouldn't like this to happen:

def foo(x : Enumerable)
  x.first
end

typeof(foo([1,2, 3])) # => Object

It's Object, according to this proposal, because x is now an Enumerable of any possible type, thus Object.

Given that you are using a type restriction A, you can use it to type the array:

def foo(x : A)
  arr = [x] of A
end

and problem solved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants