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

[RFC] Splat tuple union #223

Open
jhass opened this issue Oct 12, 2014 · 6 comments
Open

[RFC] Splat tuple union #223

jhass opened this issue Oct 12, 2014 · 6 comments

Comments

@jhass
Copy link
Member

jhass commented Oct 12, 2014

Given

class Foo
  def initialize(*args)
    @args = args
  end

  def a
    args = @args
    b(*args)
  end

  def b(*args)
    b(args)
  end

  def b(args : Enumerable(String))
    pp args
  end
end

With

Foo.new("Foo").a
Foo.new("Foo", "Bar").a

we get

args = {"Foo"}
args = {"Foo"}

instead of

args = {"Foo"}
args = {"Foo", "Bar"}

With

Foo.new("Foo", "Bar").a
Foo.new("Foo").a

we get

Error in /home/jhass/projects/crystal/splat.cr:22: index out of bounds for tuple {String}

Foo.new("Foo").a

This is inconsistent at least, but I'd also expect either variant to work.

@asterite
Copy link
Member

For now I think I'll make the compiler say an error when splatting over a union of tuples (instead of silently failing). It's a valid use case, but I wonder what was your original use case. If @args was an Array, would it still be useful for you? What do you need @args to be a tuple?

@jhass
Copy link
Member Author

jhass commented Nov 19, 2014

I think that was while toying with a macro generated Enumerator.

I don't really mind if @args is an array or a tuple, I thought the tuple was the only thing with a known size at compile time, enabling splatting in the first place. I think I would expect the compiler to generate variants of b that take the number of arguments for each tuple size in the union.

@asterite
Copy link
Member

Yes, your code should work, it's just that it's not trivial to implement because our dispatch algorithm doesn't consider different splats yet. I'll start with erroring in this case and later try to implement it.

@asterite asterite added the kind:bug A bug in the code. Does not apply to documentation, specs, etc. label Dec 1, 2014
@asterite asterite changed the title Splat argument size (incorrectly?) cached Splat tuple union Sep 30, 2015
@asterite asterite added kind:feature and removed kind:bug A bug in the code. Does not apply to documentation, specs, etc. labels Sep 30, 2015
@asterite asterite changed the title Splat tuple union [RFC] Splat tuple union Sep 30, 2015
@asterite asterite added RFC and removed kind:feature labels Sep 30, 2015
@sdogruyol
Copy link
Member

Both of these won't compile on both 0.19.4 and master.

class Foo
  def initialize(*args)
    @args = args
  end

  def a
    args = @args
    b(*args)
  end

  def b(*args)
    b(args)
  end

  def b(args : Enumerable(String))
    pp args
  end
end

Foo.new("Foo").a
Foo.new("Foo", "Bar").a

Error

Can't infer the type of instance variable '@args' of Foo

The type of a instance variable, if not declared explicitly with
`@args : Type`, is inferred from assignments to it across
the whole program.

The assignments must look like this:

  1. `@args = 1` (or other literals), inferred to the literal's type
  2. `@args = Type.new`, type is inferred to be Type
  3. `@args = Type.method`, where `method` has a return type
     annotation, type is inferred from it
  4. `@args = arg`, with 'arg' being a method argument with a
     type restriction 'Type', type is inferred to be Type
  5. `@args = arg`, with 'arg' being a method argument with a
     default value, type is inferred using rules 1, 2 and 3 from it
  6. `@args = uninitialized Type`, type is inferred to be Type
  7. `@args = LibSome.func`, and `LibSome` is a `lib`, type
     is inferred from that fun.
  8. `LibSome.func(out @args)`, and `LibSome` is a `lib`, type
     is inferred from that fun argument.

Other assignments have no effect on its type.

Can't infer the type of instance variable '@args' of Foo

    @args = args
    ^~~~~

@lbguilherme
Copy link
Contributor

Can be rewritten to:

t = rand > 0.5 ? {"Foo"} : {"Bar", "Baz"}

def f(*t)
  pp t
end

f *t

Giving:

Error in line 7: splatting a union (Tuple(String) | Tuple(String, String)) is not yet supported

@sdogruyol
Copy link
Member

Bump 👍 This still won't compile on master

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

5 participants