Killer features you could add

36 views
Skip to first unread message

OpenConcerto

unread,
Nov 28, 2011, 2:02:41 PM11/28/11
to ceylon-dev
Hi,

Congratulations about the new langage you are cooking and that we will
love!

Having used a lot of langages, I would like to share with you some
things I really loved to see in
some langage and in particular in Java.

Native concept of Mutable/Immutable Object
An easy way to break a Java application is to modify an objet that
"someone" stored in a HashSet/HashMap
because their implementations rely on Immutable objects (to be
precise, a constant hashcode).
A lot of code behave the same.
Immutable object are great for cache and memory usage reduction too.

Multiple return values
In order to have great performance and to write easily complex code,
return values should be multiple.
List<Number> list =new ArrayList<Number>();
...
Number min, Number max = getRange(list);

Number, Number getRange(List<Number> list){
Number min,max;
for( ....) // 1 pass
...
return min,max; // with no underlying array allocation, of course
}


Kind regards,

Guillaume


Gavin King

unread,
Nov 28, 2011, 2:53:09 PM11/28/11
to ceylo...@googlegroups.com
On Mon, Nov 28, 2011 at 1:02 PM, OpenConcerto

> Native concept of Mutable/Immutable Object
> An easy way to break a Java application is to modify an objet that
> "someone" stored in a HashSet/HashMap
> because their implementations rely on Immutable objects (to be
> precise, a constant hashcode).
> A lot of code behave the same.
> Immutable object are great for cache and memory usage reduction too.

Ceylon certainly encourages the use of immutability, which is one
reason for requiring the `variable` annotation. But actually having
the compiler enforce immutability becomes quite a lot more slippery
than you might imagine. How "deeply" immutable do you require? How
does the `immutable` contract on a supertype affect subtypes? etc.

I spent a lot of time on this and eventually gave up on ever resolving
all the semantic problems. Perhaps in a language without subtyping the
problem would be more tractable.

(Reminds me I need to take a third look at Fantom to remind myself
what they do for this.)

> Multiple return values
> In order to have great performance and to write easily complex code,
> return values should be multiple.
> List<Number> list =new ArrayList<Number>();
> ...
> Number min, Number max = getRange(list);
>
> Number, Number getRange(List<Number> list){
>  Number min,max;
>  for( ....)    // 1 pass
>  ...
>  return min,max;  // with no underlying array allocation, of course
> }

Support for tuples is the #1 feature request at present. I'm a bit
skeptical, but we've made sure to carefully design the type system to
be able to accommodate tuples if you guys all manage to convince me
(post-Ceylon 1.0). (Sequenced type parameters make tuples quite easily
expressible within our type system.)


--
Gavin King
gavin...@gmail.com
http://in.relation.to/Bloggers/Gavin
http://hibernate.org
http://seamframework.org

Norbert Ehreke

unread,
Nov 29, 2011, 4:46:07 AM11/29/11
to ceylon-dev
I am really surprised that tuples are in high demand. I am no language
designer, but I'll second Gavin's skepticism. I'd fear that people
would use this for returning values and state information at the same
time -- which actually constitute something that *should* be placed in
a separate class. I doubt that this really is in sync with the spirit
of Ceylon. But, hey, maybe there are compelling reasons in favor of
that kind of feature that I don't see at this point.

Gavin King

unread,
Nov 29, 2011, 10:03:04 AM11/29/11
to ceylo...@googlegroups.com
I don't think there are many truly compelling reasons, it's just a
convenience. And it remains to be seen if it's going to be a
convenience we really want in practice.

--

OpenConcerto

unread,
Nov 30, 2011, 6:30:39 AM11/30/11
to ceylon-dev
Hi,

While "someone" singing "A million months and a million days I'll try
to somehow convince you"
I took some minutes to write a so called "typical use case".

Let's consider you have millions of small arrays of integer that you
have to analyse as fast as possible
with something simple like:

private Range getRange(final int[] values) {
int min = values[0];
int max = min;
final int lenght = values.length;
for (int i = 0; i < lenght; i++) {
int v = values[i];
if (v > max) {
max = v;
} else if (v < min) {
min = v;
}
}
return new Range(min, max);
}

Performance wise, you spend 20% on Range allocations
as a good programmer, you will switch to: (loosing simplicity)

private void getRange(final Range result, final int[] values) {
int min = values[0];
int max = min;
final int lenght = values.length;
for (int i = 0; i < lenght; i++) {
int v = values[i];
if (v > max) {
max = v;
} else if (v < min) {
min = v;
}
}
result.min = min;
result.max = max;
}

As a performance guru, you will write: (loosing thread safety)
private final Range temp = new Range();

private Range getRangeOpt(final int[] values) {
int min = values[0];
int max = min;
final int lenght = values.length;
for (int i = 0; i < lenght; i++) {
int v = values[i];
if (v > max) {
max = v;
} else if (v < min) {
min = v;
}
}
temp.min = min;
temp.max = max;
return temp;
}

But with experience, if you could simply write:
int min, int max = getRange(myArray);
coding:
private int,int getRangeOpt(final int[] values) {
int min = values[0];
int max = min;
final int lenght = values.length;
for (int i = 0; i < lenght; i++) {
int v = values[i];
if (v > max) {
max = v;
} else if (v < min) {
min = v;
}
}
return min, max;
}
You will be very happy if this could perform as fast or faster than my
getRangeOpt.

At this point, I'm sure you are NOT convinced, then let's talk about
numbers using 3 tests:

private static final int ITERATION_COUNT = 50000000;
private void test1(int[] values) {
Example c = new Example();
long t1 = System.currentTimeMillis();
for (int i = 0; i < ITERATION_COUNT; i++) {
Range result = c.getRange(values);
}
long t2 = System.currentTimeMillis();
System.out.println("Test 1:" + (t2 - t1) + "ms");
}
private void test2(int[] values) {
Example c = new Example();
long t1 = System.currentTimeMillis();
final Range result = new Range();
for (int i = 0; i < ITERATION_COUNT; i++) {
c.getRange(result, values);
}
long t2 = System.currentTimeMillis();
System.out.println("Test 2:" + (t2 - t1) + "ms");

}

private void test3(int[] values) {
Example c = new Example();
long t1 = System.currentTimeMillis();

for (int i = 0; i < ITERATION_COUNT; i++) {
Range res = c.getRangeOpt(values);
}
long t2 = System.currentTimeMillis();
System.out.println("Test 3:" + (t2 - t1) + "ms");

}

Test1: 3125ms
Test2: 2532ms
Test3: 2530ms

It's not just a question of syntaxic sugar or tuple convenience
but a core issue on performance too.

From an highest perspective, having multiple parameters and multiple
return values
is a natural evolution of things; that starts to be unique and become
to be multiples.

Regards,
Guillaume

Tako Schotanus

unread,
Nov 30, 2011, 6:40:23 AM11/30/11
to ceylo...@googlegroups.com
On Wed, Nov 30, 2011 at 12:30, OpenConcerto <guillaume...@gmail.com> wrote:
Hi,

While "someone" singing "A million months and a million days I'll try
to somehow convince you"
I took some minutes to write a so called "typical use case".

<snip>

I like your example but I'm afraid that in practice a tuple would still be represented by a temporary Tuple object that we would need to instantiate. I don't see an easy way to give you tuples with the performance characteristics of your last example.

Convenience often comes at a price, a price we might be willing to pay in 95% of the cases while in the other 5% you'll knowingly have to write uglier but faster code. (That doesn't mean we've already given up, it's just that *I* at *this point* have no idea how to do what you want).

Cheers,
-Tako

OpenConcerto

unread,
Nov 30, 2011, 8:55:51 AM11/30/11
to ceylon-dev
On 30 nov, 12:40, Tako Schotanus <t...@codejive.org> wrote:

> Convenience often comes at a price, a price we might be willing to pay in
> 95% of the cases while in the other 5% you'll knowingly have to write
> uglier but faster code. (That doesn't mean we've already given up, it's
> just that *I* at *this point* have no idea how to do what you want).

I could not share your point of view at 100%,
"convenience" is for me about improvement, not regression.

Adding the concept of multiple return values is a way to improve
the performance avoiding coders to manually add tuples.
If the compiler just create an hidden "new Range(...)" (Tuple)
it is (from my point of view) useless to implement it because
introducing hidden drawbacks.

But if, because of the new concept, the compiler is able to acheive
new optimizations,
the concept is a must-have.

The example I provided is very simple, but in complex tasks, the
"emulation"
of multiple returns values has a huge cost and can heavily reduce
performance).
I saw code which spent 95% of time on this kind of thing.

To conclude, for me, a good langage is a langage that we can use
without writing ulgy/unsafe code.

Regards,
Guillaume

Tako Schotanus

unread,
Nov 30, 2011, 10:11:27 AM11/30/11
to ceylo...@googlegroups.com
But then you shouldn't be using a VM-based language at all, because like C/C++ lovers will always tell you "much better to do your own memory management". Still there are legions of Java developers out there that do brilliant work even knowing that using Java has some "hidden costs", they just don't mind because their not writing a real-time OS for example.

Of course I'm not really suggesting not to use VMs, but I only wanted to point out that convenience *often* comes at a price and *if* it is possible to do tuples without a hidden cost I'm sure we would do it, but right now I don't see how.

Cheers,
-Tako

OpenConcerto

unread,
Nov 30, 2011, 11:05:45 AM11/30/11
to ceylon-dev
On 30 nov, 16:11, Tako Schotanus <t...@codejive.org> wrote:
> Of course I'm not really suggesting not to use VMs, but I only wanted to
> point out that convenience *often* comes at a price and *if* it is possible
> to do tuples without a hidden cost I'm sure we would do it, but right now I
> don't see how.

Sure, but the goal is not to conclude "switch to C if you need
performance"
but provide new concept (from Java) to acheive better performance than
Java.

What's more, the optimization I used to avoid allocation is IMHO
doable by the ceylon compiler.
It's not an issue related to the bytecode.

Keep in mind that because Java is bytecode based, some code are faster
than C++ :)
Object allocation is something that is faster in Java than in compiled
langage.

Regards,
Guillaume

Tako Schotanus

unread,
Nov 30, 2011, 11:10:01 AM11/30/11
to ceylo...@googlegroups.com
Well actually one of my colleagues has already let me know that we *could* actually do it if we forget about Java interop (only for those methods I guess). So who knows at some time in the future ;)

Cheers,
-Tako

NikNik77771

unread,
Dec 1, 2011, 11:47:43 AM12/1/11
to ceylon-dev
I vote to do it. I work on interval library, that should be as fast as
possible, because this is just basis for complex computation. It would
be nice to have something like:

boolean double double boolean intersection(boolean lbi1, double lb1,
double rb1, boolean rbi1,
boolean lbi2, double lb2, double rb2, boolean rbi2)

That is function for intersecion of two intervals with inclusive or
exclusive boundaries.

On 30 ноя, 20:10, Tako Schotanus <t...@codejive.org> wrote:

Gavin King

unread,
Dec 1, 2011, 1:25:08 PM12/1/11
to ceylo...@googlegroups.com
I have written up something about this here, so that we don't keep
re-discussing this issue from zero every time:

https://github.com/ceylon/ceylon-spec/issues/81

On Tue, Nov 29, 2011 at 3:46 AM, Norbert Ehreke
<norbert...@googlemail.com> wrote:

--

OpenConcerto

unread,
Dec 1, 2011, 1:55:59 PM12/1/11
to ceylon-dev
Hi Gavin,

I think you should write something about performance too,
because the concept of multiple return values could introduce
performance boosts.

From my point of view, you shouldn't postpone such improvments after
1.0
because programmers are not hurry, they can wait, we have Java and
tons of other langages...
BUT to make programmers switch to Ceylon it must be as complete a
possible from day one,
seen as a revolution, different and as a mature environement.
If not, "we" will just say "Hey, it's just cold water, let's continue
with Java" and Ceylon will be
associated to second zone Java improvement. Something it shoudn't be.

One of my colleagues said me that he concluded from your example
than in a couple of days, you will remove multiple parameters
because it's always possible to write functions like:

ComputedValues myFunction(ValuesToCompute values){

}

Stupid french humour or pure logic, I don't know :)

Regards,
Guillaume

Gavin King

unread,
Dec 1, 2011, 1:59:40 PM12/1/11
to ceylo...@googlegroups.com
On Thu, Dec 1, 2011 at 12:55 PM, OpenConcerto
<guillaume...@gmail.com> wrote:

> I think you should write something about performance too,
> because the concept of multiple return values could introduce
> performance boosts.

I think it's very unlikely that this is possible on the JVM. OTOH,
Stef thinks it might be possible.

Tako Schotanus

unread,
Dec 1, 2011, 2:01:58 PM12/1/11
to ceylo...@googlegroups.com
On Thu, Dec 1, 2011 at 19:59, Gavin King <gavin...@gmail.com> wrote:
On Thu, Dec 1, 2011 at 12:55 PM, OpenConcerto
<guillaume...@gmail.com> wrote:

> I think you should write something about performance too,
> because the concept of multiple return values could introduce
> performance boosts.

I think it's very unlikely that this is possible on the JVM. OTOH,
Stef thinks it might be possible.

And not wanting to sound like a broken FLOSS-record , but: the more people actually helping the quicker it will be finished and the more things we might be able to put into 1.0 :)

-Tako

OpenConcerto

unread,
Dec 1, 2011, 2:39:09 PM12/1/11
to ceylon-dev
On 1 déc, 19:59, Gavin King <gavin.k...@gmail.com> wrote:

> I think it's very unlikely that this is possible on the JVM. OTOH,
> Stef thinks it might be possible.

Do you mean that the 'static trick' I used to avoid the memory
allocation is not possible on the JVM? :)

Regards,
Guillaume

Stephane Epardaud

unread,
Dec 1, 2011, 2:47:11 PM12/1/11
to ceylo...@googlegroups.com


On 1 December 2011 20:39, OpenConcerto <guillaume...@gmail.com> wrote:
Do you mean that the 'static trick' I used to avoid the memory
allocation is not possible on the JVM? :)

That static trick is just not possible if we want to be thread-safe, unless we make it thread-local but then you lose the speed benefits.
--
Stéphane Épardaud

Tako Schotanus

unread,
Dec 1, 2011, 2:47:27 PM12/1/11
to ceylo...@googlegroups.com
Well for one, how would you handle:

while (...) {
   list.add(getSomeTuple());
}

intuitively this should be possible but would fail in your example which would mean that you have to know somehow that in this case a copy will have to be made.

Tako Schotanus

unread,
Dec 1, 2011, 2:49:13 PM12/1/11
to ceylo...@googlegroups.com
I still think we should go for JavaScript's/Dart's version of thread safety: no shared state at all and only message passing allowed.

Yeah won't happen, I know ^^

Stephane Epardaud

unread,
Dec 1, 2011, 3:04:48 PM12/1/11
to ceylo...@googlegroups.com


On 1 December 2011 19:59, Gavin King <gavin...@gmail.com> wrote:
I think it's very unlikely that this is possible on the JVM. OTOH,
Stef thinks it might be possible.

Right, so http://java.sun.com/docs/books/jvms/second_edition/html/Compiling.doc.html#14787 says that the JVM manages the stack and that we can't push an extra return value on the caller's frame, mostly because even if that caller managed to allocate a stack entry for the extra values, the callee can't operate on the caller's stack since it doesn't know its address.
So it looks like we're out of ideas.
--
Stéphane Épardaud

Ross Tate

unread,
Dec 1, 2011, 3:56:44 PM12/1/11
to ceylo...@googlegroups.com
Have a class Tuple<T...>. For methods that return Tuple<T..> make a specialization. That specialization takes an Out for each extra component of the tuple, then upon returning returns only the first component of the tuple and writes the rest to the Outs. Then a caller who just extracts the values from the returned tuple can switch to the specialization and provide Outs. Because these Outs are invisible to the user, they can be untyped and unreified and they are guaranteed not to be stored, so such a caller can reuse the same Outs many times and avoid allocations. In fact, the specialized method returning a tuple can even reuse the Outs provided to it. The cost is code duplication.

Tako Schotanus

unread,
Dec 1, 2011, 4:59:20 PM12/1/11
to ceylo...@googlegroups.com
On Thu, Dec 1, 2011 at 21:56, Ross Tate <rt...@cs.ucsd.edu> wrote:
Have a class Tuple<T...>. For methods that return Tuple<T..> make a specialization. That specialization takes an Out for each extra component of the tuple, then upon returning returns only the first component of the tuple and writes the rest to the Outs. Then a caller who just extracts the values from the returned tuple can switch to the specialization and provide Outs. Because these Outs are invisible to the user, they can be untyped and unreified and they are guaranteed not to be stored, so such a caller can reuse the same Outs many times and avoid allocations. In fact, the specialized method returning a tuple can even reuse the Outs provided to it. The cost is code duplication.

Again being a bit dense, could you provide a bit more information about this? :)

Thanks,
-Tako

Ross Tate

unread,
Dec 1, 2011, 5:24:36 PM12/1/11
to ceylo...@googlegroups.com
Heheh, sorry, I'm still used to face-to-face conversation alongside a whiteboard. It'll take me a while to get used to e-mail.

Take the following (impractical but illustrative) example:

Tuple<nat,nat> foo(nat n) {
  return (n % 10, n / 10);
}

Tuple<nat,nat> bar(nat n) {
  nat x = 0;
  nat y = 0;
  for (nat i = 1 to n) {
    (xi, yi) = foo(i*i);
    x = max(x, xi);
    y = max(y, yi);
  }
  return (x, y);
}

int baz() {
  (x, y) = bar(100);
  return x - y;
}

We can rewrite it with the following:

class Out {Object out;}

nat foo_out(nat n, Out out) {
  out.out = n / 10;
  return n % 10;
}

nat bar_out(nat n, Out out) {
  nat x = 0;
  nat y = 0;
  for (nat i = 0 to n) {
    nat xi = foo_out(i*i, out);
    x = max(x, xi);
    y = max(y, (nat)out.out);
  }
  out.out = y;
  return x;
}

int baz() { //completely replaces the original
  Out out = new Out();
  nat x = bar_out(100, out);
  return x - (nat)out.out;
}

My optimization has only 1 allocation instead of 101.

Emmanuel Bernard

unread,
Dec 1, 2011, 5:30:47 PM12/1/11
to ceylo...@googlegroups.com, ceylo...@googlegroups.com
I am slightly out of my league and that's mostly speculative (I haven't had time to dig in) but your message passing model would have to be implemented with some kind of shared state anyways. The queue in this case. 

Or is there some magic trick I am not aware of in all these concurrency models?

Granted it simplifies the user experience but that's just simplifying the model by disallowing things. If we can find a model that share state when explicitly requested like the non shared / shared approach we have for visibility, this could be a nice step to reduce concurrency bugs. 

But I digress. 

Gavin King

unread,
Dec 1, 2011, 5:33:15 PM12/1/11
to ceylo...@googlegroups.com
So this is sortof related to Stef's suggestion to use a ThreadLocal,
except that instead of using Java's ThreadLocal which sticks the
values on the Thread object, IIRC, you emulate the effect of a thread
local by munging the signature of all methods to *explicitly*
propagate the holder object down the stack.

Interesting idea.

--

Tako Schotanus

unread,
Dec 1, 2011, 5:40:20 PM12/1/11
to ceylo...@googlegroups.com
Well yes, you disallow certain things but in exchange you get the certainty you (or 3rd party code) can't do anything wrong. I don't know if a good message passing / actor framework can also help with race conditions and such but it is an improvement.

And of course the implementation of the message passing / actors would need some kind of shared state (shared memory, sockets whatever) but that would be a tested component hidden from the user's prying fingers. The same way that on the inside of functional languages like ML or Haskell the compiler can actually generate code that uses mutable state, but as long as they have guaranteed that it works okay you don't have to think about it.

But this was just a remark, I wasn't actually seriously suggesting anything ^^

Tako Schotanus

unread,
Dec 1, 2011, 5:43:53 PM12/1/11
to ceylo...@googlegroups.com
But couldn't you just pass the Tuple down the stack? Why this Out object?

Ross Tate

unread,
Dec 1, 2011, 5:45:11 PM12/1/11
to ceylo...@googlegroups.com
So this is sortof related to Stef's suggestion to use a ThreadLocal,
except that instead of using Java's ThreadLocal which sticks the
values on the Thread object, IIRC, you emulate the effect of a thread
local by munging the signature of all methods to *explicitly*
propagate the holder object down the stack.

That sounds right. I don't know much about ThreadLocal, but that could work too (and maybe better). One nice thing about having separate signatures is you keep compatibility with uses that don't want the specialization. Furthermore, the use has to actively switch to call the specialization, so you don't really have to worry about someone accidentally using the specialization and then not following the changed protocol.

Ross Tate

unread,
Dec 1, 2011, 5:51:51 PM12/1/11
to ceylo...@googlegroups.com
But couldn't you just pass the Tuple down the stack? Why this Out object?

First, a Tuple would have to be reified, so you'd have to do other things there when reusing the same Tuple for different types. Second, I figured returning was more efficient to writing to and reading from a field in the heap, so I wanted to optimize for that as well. Third, it ensures at the bytecode level that there isn't some sort of leak; one of the guarantees of Out is that it's never stored which is why we're safe to reuse the same one over and over.

Regardless, the basic idea was returning by a reusable out-parameter to reduce allocations. The specifics aren't too important, and we could use a Tuple instead.

NikNik77771

unread,
Dec 2, 2011, 8:44:15 AM12/2/11
to ceylon-dev

Tako Schotanus

unread,
Dec 2, 2011, 9:30:28 AM12/2/11
to ceylo...@googlegroups.com
I'm not sure that is a compelling reason ^^
(not to do with Kotlin but just with any remark of the type "but language X has this feature")

-Tako

Gavin King

unread,
Dec 2, 2011, 9:32:58 AM12/2/11
to ceylo...@googlegroups.com
On Fri, Dec 2, 2011 at 8:30 AM, Tako Schotanus <ta...@codejive.org> wrote:
> I'm not sure that is a compelling reason ^^
> (not to do with Kotlin but just with any remark of the type "but language X
> has this feature")

Also note that Kotlin doesn't have union types, and one of the main
legs of my argument as to why *we* don't need this is that we *do*
have union types.

Stephane Epardaud

unread,
Dec 2, 2011, 9:33:37 AM12/2/11
to ceylo...@googlegroups.com
But, but… Perl has *this* feature! https://github.com/ceylon/ceylon-spec/issues/84 ;)
--
Stéphane Épardaud

Gavin King

unread,
Dec 2, 2011, 9:35:54 AM12/2/11
to ceylo...@googlegroups.com
On Fri, Dec 2, 2011 at 8:33 AM, Stephane Epardaud
<stephane...@gmail.com> wrote:
> But, but… Perl has *this*
> feature! https://github.com/ceylon/ceylon-spec/issues/84 ;)

But, but... OCaml and Erlang have *this* one:
https://github.com/ceylon/ceylon-spec/issues/82

Tako Schotanus

unread,
Dec 2, 2011, 9:35:35 AM12/2/11
to ceylo...@googlegroups.com
On Fri, Dec 2, 2011 at 15:32, Gavin King <gavin...@gmail.com> wrote:
On Fri, Dec 2, 2011 at 8:30 AM, Tako Schotanus <ta...@codejive.org> wrote:
> I'm not sure that is a compelling reason ^^
> (not to do with Kotlin but just with any remark of the type "but language X
> has this feature")

Also note that Kotlin doesn't have union types, and one of the main
legs of my argument as to why *we* don't need this is that we *do*
have union types.

Ok, that's interesting, so how would you see us using union types to do more or less the same things that other languages use tuples for?

-Tako 

Gavin King

unread,
Dec 2, 2011, 9:41:28 AM12/2/11
to ceylo...@googlegroups.com
On Fri, Dec 2, 2011 at 8:35 AM, Tako Schotanus <ta...@codejive.org> wrote:

>> Also note that Kotlin doesn't have union types, and one of the main
>> legs of my argument as to why *we* don't need this is that we *do*
>> have union types.
>>
> Ok, that's interesting, so how would you see us using union types to do more
> or less the same things that other languages use tuples for?

No, it's not a true replacement for tuples. Rather I see us using union types to
do more or less the same things that other languages *misuse* tuples for.

Stephane Epardaud

unread,
Dec 2, 2011, 9:51:10 AM12/2/11
to ceylo...@googlegroups.com


On 2 December 2011 15:41, Gavin King <gavin...@gmail.com> wrote:
No, it's not a true replacement for tuples. Rather I see us using union types to
do more or less the same things that other languages *misuse* tuples for.

Right, but we're left with not being able to use Tuples properly then ;)
--
Stéphane Épardaud

Tako Schotanus

unread,
Dec 2, 2011, 10:03:26 AM12/2/11
to ceylo...@googlegroups.com
On Fri, Dec 2, 2011 at 15:41, Gavin King <gavin...@gmail.com> wrote:
On Fri, Dec 2, 2011 at 8:35 AM, Tako Schotanus <ta...@codejive.org> wrote:

>> Also note that Kotlin doesn't have union types, and one of the main
>> legs of my argument as to why *we* don't need this is that we *do*
>> have union types.
>>
> Ok, that's interesting, so how would you see us using union types to do more
> or less the same things that other languages use tuples for?

No, it's not a true replacement for tuples. Rather I see us using union types to
do more or less the same things that other languages *misuse* tuples for.

I understand, I'd just like to see some kind of example :) 

Gavin King

unread,
Dec 2, 2011, 10:26:58 AM12/2/11
to ceylo...@googlegroups.com
On Fri, Dec 2, 2011 at 8:51 AM, Stephane Epardaud
<stephane...@gmail.com> wrote:

>> No, it's not a true replacement for tuples. Rather I see us using union
>> types to do more or less the same things that other languages *misuse*
>> tuples for.
>
>
> Right, but we're left with not being able to use Tuples properly then ;)

Correct :-)

Gavin King

unread,
Dec 2, 2011, 10:28:29 AM12/2/11
to ceylo...@googlegroups.com
On Fri, Dec 2, 2011 at 9:03 AM, Tako Schotanus <ta...@codejive.org> wrote:

> I understand, I'd just like to see some kind of example :)

This very common "pattern" in languages with tuples:

result, error = doSomethingThatMightFail(path)

Tako Schotanus

unread,
Dec 2, 2011, 10:53:12 AM12/2/11
to ceylo...@googlegroups.com
On Fri, Dec 2, 2011 at 16:28, Gavin King <gavin...@gmail.com> wrote:
On Fri, Dec 2, 2011 at 9:03 AM, Tako Schotanus <ta...@codejive.org> wrote:

> I understand, I'd just like to see some kind of example :)

This very common "pattern" in languages with tuples:

   result, error = doSomethingThatMightFail(path)


I meant an example of Ceylon code that will make that kind of tuple-support not necessary or are you telling me that the above is actually valid Ceylon code? 

Tom Bentley

unread,
Dec 2, 2011, 10:57:15 AM12/2/11
to ceylo...@googlegroups.com

I think Gavin's trying to say that where other languages (with tuples and destructuring) would use this:

   result, error = doSomethingThatMightFail(path)


in Ceylon we can do this:

Result|Error result = doSomethingThatMightFail(path);
switch (result) {
  case is Result:
    // do something with the result
  case is Error:
    //handle error
}

Gavin King

unread,
Dec 2, 2011, 10:58:44 AM12/2/11
to ceylo...@googlegroups.com
On Fri, Dec 2, 2011 at 9:53 AM, Tako Schotanus <ta...@codejive.org> wrote:

>> > I understand, I'd just like to see some kind of example :)
>>
>> This very common "pattern" in languages with tuples:
>>
>>    result, error = doSomethingThatMightFail(path)
>>
>>
> I meant an example of Ceylon code that will make that kind of tuple-support
> not necessary or are you telling me that the above is actually valid Ceylon
> code?

In Ceylon you would return Result|Error and do:

switch (doSomethingThatMightFail(path))
case (is Result) { ... }
case (is Error) { ... }

Stephane Epardaud

unread,
Dec 2, 2011, 11:04:32 AM12/2/11
to ceylo...@googlegroups.com
Awwww… You guys are so cute :)

Tako Schotanus

unread,
Dec 2, 2011, 11:20:35 AM12/2/11
to ceylo...@googlegroups.com
On Fri, Dec 2, 2011 at 16:58, Gavin King <gavin...@gmail.com> wrote:
On Fri, Dec 2, 2011 at 9:53 AM, Tako Schotanus <ta...@codejive.org> wrote:

>> > I understand, I'd just like to see some kind of example :)
>>
>> This very common "pattern" in languages with tuples:
>>
>>    result, error = doSomethingThatMightFail(path)
>>
>>
> I meant an example of Ceylon code that will make that kind of tuple-support
> not necessary or are you telling me that the above is actually valid Ceylon
> code?

In Ceylon you would return Result|Error and do:

   switch (doSomethingThatMightFail(path))
   case (is Result) { ... }
   case (is Error) { ... }


Hmm but that's not really the same isn't it, and by far not the only or even the most common use of tuples (except maybe for a language like Python hehe) 

In this example it really *is* a kind of union, a C union, it either returns a result and for certain values of the result (let's say null or 0) there might be an additional value that contains the error. But there are many examples that can be made where you're actually returning 2 necessary values. And for Ceylon I guess those are the only ones that are really interesting.

-Tako

PS: thx Tom :)

OpenConcerto

unread,
Dec 2, 2011, 1:06:44 PM12/2/11
to ceylon-dev
Hi,

what do you think about this thread safe version of my example?

private static final ThreadLocal<Range> tmp = new ThreadLocal<Range>()
{
        @Override
        protected Range initialValue() {
            return new Range();
        }
    };

    private Range getRangeOpt2(final int[] values) {
        int min = values[0];
        int max = min;
        final int lenght = values.length;
        for (int i = 0; i < lenght; i++) {
            int v = values[i];
            if (v > max) {
                max = v;
            } else if (v < min) {
                min = v;
            }
        }
        final Range range = tmp.get();
        range.min = min;
        range.max = max;
        return range;
    }


Regards,
Guillaume

Reply all
Reply to author
Forward
0 new messages