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
> 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
--
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
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>
> 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
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
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:
https://github.com/ceylon/ceylon-spec/issues/81
On Tue, Nov 29, 2011 at 3:46 AM, Norbert Ehreke
<norbert...@googlemail.com> wrote:
--
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
> 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.
On Thu, Dec 1, 2011 at 12:55 PM, OpenConcertoI think it's very unlikely that this is possible on the JVM. OTOH,
<guillaume...@gmail.com> wrote:
> I think you should write something about performance too,
> because the concept of multiple return values could introduce
> performance boosts.
Stef thinks it might be possible.
> 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
Do you mean that the 'static trick' I used to avoid the memory
allocation is not possible on the JVM? :)
I think it's very unlikely that this is possible on the JVM. OTOH,
Stef thinks it might be possible.
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.
Interesting idea.
--
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.
But couldn't you just pass the Tuple down the stack? Why this Out object?
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.
But, but... OCaml and Erlang have *this* one:
https://github.com/ceylon/ceylon-spec/issues/82
On Fri, Dec 2, 2011 at 8:30 AM, Tako Schotanus <ta...@codejive.org> wrote:Also note that Kotlin doesn't have union types, and one of the main
> 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")
legs of my argument as to why *we* don't need this is that we *do*
have union types.
>> 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.
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.
On Fri, Dec 2, 2011 at 8:35 AM, Tako Schotanus <ta...@codejive.org> wrote:No, it's not a true replacement for tuples. Rather I see us using union types to
>> 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?
do more or less the same things that other languages *misuse* 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.
>
>
> Right, but we're left with not being able to use Tuples properly then ;)
Correct :-)
> I understand, I'd just like to see some kind of example :)
This very common "pattern" in languages with tuples:
result, error = doSomethingThatMightFail(path)
On Fri, Dec 2, 2011 at 9:03 AM, Tako Schotanus <ta...@codejive.org> wrote:This very common "pattern" in languages with tuples:
> I understand, I'd just like to see some kind of example :)
result, error = doSomethingThatMightFail(path)
result, error = doSomethingThatMightFail(path)
>> > 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) { ... }
On Fri, Dec 2, 2011 at 9:53 AM, Tako Schotanus <ta...@codejive.org> wrote:In Ceylon you would return Result|Error and do:
>> > 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?
switch (doSomethingThatMightFail(path))
case (is Result) { ... }
case (is Error) { ... }
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