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

return more than one value from a for-comprehension #860

Open
FroMage opened this issue Nov 26, 2013 · 12 comments
Open

return more than one value from a for-comprehension #860

FroMage opened this issue Nov 26, 2013 · 12 comments

Comments

@FroMage
Copy link
Member

FroMage commented Nov 26, 2013

I know we can do that with something that flattens the resulting comprehension afterwards, but it could be useful to support "returning" more than one value from a comprehension:

assert({1, 10, 2, 20, 3, 30}, {for (i in 1..3) *{i, i*10}});

Where I reuse the * operator to spread more than one value in the comprehension.

@gavinking
Copy link
Member

I know we can do that with something that flattens the resulting comprehension afterwards

It's called expand() ;-)

but it could be useful to support "returning" more than one value from a comprehension:

Interesting. So basically you're providing flatMap() as part of the comprehension syntax. It looks pretty reasonable to me.

@FroMage
Copy link
Member Author

FroMage commented Nov 26, 2013

I love how you can say expand and flatMap in the same comment without realising that expand should really be called flatten ;)

@quintesse
Copy link
Member

Be careful with what you say, he might just rename flatMap to expandMap!

@gavinking
Copy link
Member

Oh I realize that, but then I would have to find a new name for the arguably deeper and more basic operation that is currently called flatten().

@gavinking
Copy link
Member

OK, so this issue us actually way more important than I had realized. For #807, we need something almost exactly like this. Unfortunately, the syntax that makes sense for #807 is this:

    Div {
        for (sect in sections) { 
            Title(sect.title), 
            Text(sect.text) 
        }
    }

Not, as proposed by @FroMage:

    Div {
        for (sect in sections) *{ 
            Title(sect.title), 
            Text(sect.text) 
        }
    }

But the first syntax has a huge problem. It naturally means a comprehension producing iterables! Now I'm regretting not having required an extra punctuation character in our comprehension syntax, for example:

    [ for (i in 1..10) : i^2 ]

That would have spared us from this ambiguity :-(

@gavinking
Copy link
Member

FTR, today you can write this as:

Div {
    *expand {
        for (sect in sections) { 
            Title(sect.title), 
            Text(sect.text) 
        }
    }
}

But this involves a whole extra level of nesting, and two rather technical constructs, the *, and the expand() function.

@FroMage
Copy link
Member Author

FroMage commented Dec 4, 2013

I think this will become part of a bigger debate over the syntax, because I presume people will also want to be able to do:

Div {
    for (sect in sections) { 
        Title(sect.title), 
        Text(sect.text) 
    },
    for (para in paragraphs) { 
        Title(para.title), 
        Text(para.text) 
    },
    if (needsSomething) {
      Text(something)
    }
}

@gavinking
Copy link
Member

That's #807 of which this is just a part.

@gavinking
Copy link
Member

So there is a workaround, with what we have today. A framework could define a Fragment class that is essentially ignored, and is just a holder for children. Then you could write:

Div {
    for (sect in sections)
        Fragment {
            Title(sect.title), 
            Text(sect.text) 
        }
}

That's not perfect, but I think it's OK.

@gavinking
Copy link
Member

Well, hrm, @drochetti is already way ahead of me here and he actually already supports almost the same idea in ceylon.html but he just uses Iterable, so you can write, simply:

Div {
    for (sect in sections) {
        Title(sect.title), 
        Text(sect.text) 
    }
}

The downside of that is that Iterables don't cleanly nest like Fragments do. So I can't add another nested for.

@gavinking
Copy link
Member

A further alternative would be to put the * at the front of the comprehension. That's less intuitive, but perhaps it's easier on the eyes. Compare:

Div {
    *for (sect in sections) {
        Title(sect.title), 
        Text(sect.text) 
    }
}

With:

Div {
    for (sect in sections) *{
        Title(sect.title), 
        Text(sect.text) 
    }
}

@gavinking
Copy link
Member

We should go with the prefix * because it avoid the appearance of irregularity between if comprehensions #869 and if expressions #503. I think it's also a little easier on the eyes.

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