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

Typing an instance variable as a generic module with specific type #2459

Closed
waterlink opened this issue Apr 15, 2016 · 10 comments
Closed

Typing an instance variable as a generic module with specific type #2459

waterlink opened this issue Apr 15, 2016 · 10 comments

Comments

@waterlink
Copy link
Contributor

# first I have a generic Factory abstract module (kind of interface/protocol)
module Factory(T)
  abstract def build : T
end

# then somewhere in some class I want to accept a certain factory:
@reporter_factory : Factory(Reporter)

This results in this error:

Spec2::Factory(T) is not a generic class, it's a generic module

I can't understand, why this should not work. Because include Factory(Reporter) and extend Factory(Reporter) works just fine.

@waterlink
Copy link
Contributor Author

I can of course create duplicated protocols with names ReporterFactory, RunnerFactory, OrderFactory and so on. But this does not feel clean to me..

@asterite
Copy link
Member

This is a current limitation, you can't have a variable typed with a generic module. This is why I had to remove Iterator#flatten, it needed a variable of type Iterator(T).

This will definitely be in the future language.

@waterlink
Copy link
Contributor Author

waterlink commented Apr 15, 2016

@asterite What I am really looking for here is protocol/interface feature, for example:

protocol Factory(T)
  def build : T
end

class ReporterFactory
  # similar to include
  implements Factory(Reporter)

  def build
    Reporter.new(...)
  end
end

# or:
class Reporter
  # similar to extend
  class_implements Factory(Reporter)

  def self.build
    new(...)
  end
end

What do you think about that kind of feature? It is very similar to how modules currently work, but modules are majorly used for code re-use. Here protocols are purely abstract.

@jhass
Copy link
Member

jhass commented Apr 15, 2016

I'd love to see modules reused for protocols, I think it fits more naturally than adding yet another construct to the language (but then I already see abstract classes redundant to modules). A compromise could be something like abstract module Foo to forbid carrying implementations, though I see no real reason to.

@waterlink
Copy link
Contributor Author

@jhass Sure, that would work for my tastes too.

@waterlink
Copy link
Contributor Author

@asterite @jhass

For now I have gone with something along these lines:

macro def_abstract_factory
  module Factory
    abstract def build : {{@type}}
  end
end

module Reporter
  def_abstract_factory
  abstract def report_stuff(stuff : String)
end

class MyReporter
  include Reporter
  extend Reporter::Factory

  def self.build : Reporter
    new
  end

  def report_stuff(stuff : String)
    "stuff was: #{stuff}"
  end
end

def configure_reporter(r : Reporter::Factory)
  r.build.report_stuff("some specific stuff")
end

configure_reporter(MyReporter)

@waterlink
Copy link
Contributor Author

@asterite Maybe I could implement that feature, if you could guide me through relevant places in the compiler? Where should I start looking (and which parts I need to understand)?

@asterite
Copy link
Member

@waterlink The problem is that the way generic types are modelled is not correct, and I need to review that with @waj

Another issue that I don't know yet how we'll solve it is that all tuple types include Enumerable, but before knowing what tuples you have in your problem you don't know which are enumerable... well, after the type inference finishes you know that, but the idea of the whole change in the type inference was to know the whole type hierarchy before starting the type inference (well, it's a similar thing with generics...). Kind of hard to explain... maybe after 0.17.0, right now I want to release soon with all the named args features.

@asterite
Copy link
Member

@waterlink What I mean is, it's not that I don't implement it because of lack of time, I don't do it because I don't know what the correct way to do that would be... and also, the current way that generics are implemented is also not optimal, so the whole thing needs a redesign.

@asterite
Copy link
Member

Closed in favor of #2665

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

3 participants