How can I get an element of a tuple when the tuple may be null?

40 views
Skip to first unread message

Renato Athaydes

unread,
May 24, 2015, 2:45:05 PM5/24/15
to ceylon...@googlegroups.com
I have the following simplified code:

[Integer, String]? x = [1, ""];

I want to get either element of the tuple. Problem being, cannot do it without losing the type information.

Examples:

String? s = x?[1];       // incorrect syntax
String? s = x?.get(1); // cannot assign String|Integer?
String? s = x?.last     // cannot assign String|Integer?

I got it working like this:

String? s = if (exists x) then x[1] else null; // OK!

But it feels unsatisfying... in particular, I believe the first example above should have worked...

value x = [2, "hi"];
String s = x[1];      // OK

[Integer, String] y = [3, "ho"];
String? s = x?[1];   // invalid syntax :(

Why doesn't the syntax allow that?

PS: the real use case is this: I need to get the longest list in a list of lists, so I sort the lists by size and get the first list:

{{Integer*}*} list = { {1, 2}, {4, 3, 2} }; // example

value longest = [ for (c in list) [c.size, c] ]
                    .sort((first, sec) => first[0] <=> sec[0])
                    .first?.last else {}; // just need the longest list
// Not good, type of longest is Integer|{Integer*}
// because of the problem I explained above

PS2: getting the sizes of the Iterables may be expensive but that does not matter in this example

Renato Athaydes

unread,
May 24, 2015, 2:58:19 PM5/24/15
to ceylon...@googlegroups.com
Sorry the unformatted code and some mistakes in the post above, here's a fixed post:


I have the following simplified code:

[Integer, String]? x = [1, ""];

I want to get either element of the tuple. Problem being, cannot do it without losing the type information.

Examples:

String? s = x?[1]; // incorrect syntax
String? s = x?.get(1); // cannot assign String|Integer?
String? s = x?.last // cannot assign String|Integer?

I got it working like this:

String? s = if (exists x) then x[1] else null; // OK!

But it feels unsatisfying... in particular, I believe the first example above should have worked...

value x = [2, "hi"];
String s = x[1]; // OK

[Integer, String]? y = [3, "ho"];
String? s = y?[1]; // invalid syntax :(

Why doesn't the syntax allow that?

BTW: why does x[1] returns a String, but x.get(1) returns String|Integer|Null in the above example (I thought the value[] notation was sugar for get() )??

John Vasileff

unread,
May 24, 2015, 3:13:55 PM5/24/15
to ceylon...@googlegroups.com
One option:

    {Integer*}? longest = [ for (c in list) [c.size, c] ]

       .sort((first, sec) => first[0] <=> sec[0])
       .first?.rest?.first;

John

--
You received this message because you are subscribed to the Google Groups "ceylon-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ceylon-users...@googlegroups.com.
To post to this group, send email to ceylon...@googlegroups.com.
Visit this group at http://groups.google.com/group/ceylon-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/ceylon-users/da9769af-f4ba-4201-911d-8179e082df32%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Renato Athaydes

unread,
May 24, 2015, 3:15:22 PM5/24/15
to ceylon...@googlegroups.com
Just figured out a better solution!

value longest = [ for (c in list) [c, c.size] ]
                   
.sort((first, sec) => first[1] <=> sec[1])
                   
.last?.first else {};

Just changed the position of the lists and their sizes!

This works because first, unlike last, returns the right type on a Tuple.

So, this works:

[String, Integer] x = ["", 0];
String s = x.first;

But this, doesn't:

[Integer, String] x = [0, ""];
String s = x.last;

I know, that's because of the type parameters of Tuple.... still not so natural, but that makes sense.

Ross Tate

unread,
May 24, 2015, 3:26:23 PM5/24/15
to ceylon...@googlegroups.com
This is an interesting question. I'm surprised x?[1] doesn't work. It might be cool if `if (exists [s, i] = x) ...` worked as well.

--
You received this message because you are subscribed to the Google Groups "ceylon-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ceylon-users...@googlegroups.com.
To post to this group, send email to ceylon...@googlegroups.com.
Visit this group at http://groups.google.com/group/ceylon-users.

Gavin King

unread,
May 24, 2015, 3:46:07 PM5/24/15
to ceylon...@googlegroups.com
Renato, this works well:

[Integer, String]? x = [1, ""];
if (exists [i, s] = x) {
//...
}

By the way, very very early versions of the Ceylon spec had a x?[i]
operator. If you would like to see it come back, you could submit an
issue against ceylon-spec. I'm not against it.
> --
> You received this message because you are subscribed to the Google Groups
> "ceylon-users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to ceylon-users...@googlegroups.com.
> To post to this group, send email to ceylon...@googlegroups.com.
> Visit this group at http://groups.google.com/group/ceylon-users.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/ceylon-users/da9769af-f4ba-4201-911d-8179e082df32%40googlegroups.com.
>
> For more options, visit https://groups.google.com/d/optout.



--
Gavin King
ga...@ceylon-lang.org
http://profiles.google.com/gavin.king
http://ceylon-lang.org
http://hibernate.org
http://seamframework.org

Gavin King

unread,
May 24, 2015, 3:47:32 PM5/24/15
to ceylon...@googlegroups.com
Or this, of course:

String? str = if (exists [i, s] = x) then s else null;

Renato Athaydes

unread,
May 24, 2015, 4:03:31 PM5/24/15
to ceylon...@googlegroups.com

Or this, of course:

    String? str = if (exists [i, s] = x) then s else null;


Very cool...

I think x?[n] should be allowed for the sake of regularity in the language.
But then, how about maybe null functions:

String fun(String(String)? maybeFun) {
   
return maybeFun?("hi") else "";
}

It's kind of the same kind of situation!?

On the other thing I mentioned, shouldn't the type-checker interpret x[1] and x.get(1) in the same manner (AFAIK the runtime does think these are the same!?).

I will create issues for this if you think these are feasible.

Renato

Gavin King

unread,
May 24, 2015, 4:05:23 PM5/24/15
to ceylon...@googlegroups.com
And then what about null parameters?

And then what about x*[1], x*(args) etc?

It's a slippery slope, which is why we need to stop somewhere.
> --
> You received this message because you are subscribed to the Google Groups
> "ceylon-users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to ceylon-users...@googlegroups.com.
> To post to this group, send email to ceylon...@googlegroups.com.
> Visit this group at http://groups.google.com/group/ceylon-users.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/ceylon-users/49c05162-9428-452b-ab23-df4f90f68ac5%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages