Re: [ceylon-users] Some issues with ceylon M5

71 views
Skip to first unread message

Tom Bentley

unread,
Apr 24, 2013, 4:31:15 PM4/24/13
to ceylon...@googlegroups.com
Hi William,

>
I've come accross a few issues (noted as Backend Errors)

Whenever the IDE reports a "back end error" it's basically a bug in the compiler. Please open an issue against ceylon-compiler (i.e. https://github.com/ceylon/ceylon-compiler/issues/new) for any that you encounter.

Your ListenerHelper class compiles in the IDE fine for me, using the most recent "dev channel" version of the IDE, so it may be these are bugs that have been fixed since M5 was released.

Your other problem stems from the declaration of helper as being of type
    ListenerHelper<[ObservableValue<String>]>
but when you call addListener() you're assuming its of type
    ListenerHelper<[ ObservableValue<String> , String?, String?]>

In other words although the Strings are optional they still need values (or nulls) to the present in the tuple.

I can see you're trying to abstract over listeners which take the pre- and post-change values and those that do not. To be honest I don't see a clean way of doing this, as it amounts to overloading of fireEvent(). Your current approach essentially allows listener() to be called with two or four or more arguments, instead of just the 1 or 3 arguments you seem to intend.

Perhaps someone cleverer than me can figure something out though.

Tom


On 24 April 2013 19:00, William Draï <willia...@gmail.com> wrote:
Hi all,

I've just started to play with Ceylon and I have to say that I'm quite impressed by the current status of the language and tools (I'm using Ceylon IDE M5).
However when trying to build a quick prototype of a data binding module (à la javafx), I've come accross a few issues (noted as Backend Errors) and I'm not sure if the problem is me (most likely) or the compiler.
I'll start by one of these issues and a short question (I have some more but this would transform this post in a Marcel Proust's novel...) :

My goal is to have a generic helper class which can handle addXXListener/removeXXListener for any kind a listener method (i.e. any list of arguments), for example :

ListenerHelper<[Observable<Value>]> invalidationListenersHelper = ListenerHelper<[Observable<Value>]>();
ListenerHelper<[ObservableValue<Value>, Value?, Value?]> changeListenersHelper = ListenerHelper<[ObservableValue<Value>, Value?, Value?]>();

invalidationListenersHelper.addListener(listener);
invalidationListenersHelper.fireEvent([ observable ]);
or 
changeListenersHelper.addListener(listener);
changeListenersHelper.fireEvent([ observable, oldValue, newValue ]);

Here is the class I've written to do this :
class ListenerHelper<Args>() given Args satisfies Anything[] {
alias Listener => Callable<Anything, Args>;

variable Array<Listener> listeners = array<Listener>([]);
shared void addListener(Callable<Anything, Args> listener) {
if (listeners.contains(listener)) {
return;
}
Array<Listener> newListeners = arrayOfSize(listeners.size+1, listener);
listeners.copyTo(newListeners, 0, 0, listeners.size);
listeners = newListeners;
}
shared void removeListener(Callable<Anything, Args> listener) {
variable Integer index = 0;
for (i->l in listeners.indexed) {
if (l == listener) {
index = i;
break;
}
}
Array<Listener> newListeners = arrayOfSize(listeners.size+1, listener);
if (index > 0) {
listeners.copyTo(newListeners, 0, 0, index);
}
if (index < listeners.size) {
listeners.copyTo(newListeners, index+1, index, listeners.size-index-1);
}
listeners = newListeners;
}

shared void fireEvent(Args args) {
listeners.map((Listener listener) => listener(args));
}
}

The following line :
listeners.map((Listener listener) => listener(args));

does not compile with the error :
[Backend error] Compiler error: java.lang.IndexOutOfBoundsException: Index: 0, Size: 0

Also tried this but same error :
shared void fireEvent(Anything* args) {
listeners.map((Listener listener) => listener(args));
}

I don't know what's the problem, maybe what I'm trying to do is not possible to achieve this way.

Another question on the same class. I've tried first to define Listener as Callable<Nothing, Args> because listeners are supposed to be void, but when doing this, I cannot use a void method as a listener for some reason. So this does not work when addListener is declared with addListener(Callable<Nothing, Args>) :

void listener(ObservableValue<String> prop, String? oldVal, String? newVal) {
    changed = true;
}

ListenerHelper<[ ObservableValue<String> ]> helper = ListenerHelper<[ ObservableValue<String> ]>();
helper.addListener(listener); 

The error is not a backend error this time :
argument must be assignable to parameter listener of addListener: Anything(ObservableValue<String>, String?, String?) is not assignable to Nothing(ObservableValue<String>)

If I understand correctly void listener(args) is not a Nothing(Args), so how would I declare a method so it's a Nothing(Args) ? Maybe there is something more void than void ?


Thanks for your help.

--
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?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

William Draï

unread,
Apr 24, 2013, 5:36:57 PM4/24/13
to ceylon...@googlegroups.com
Hi Tom,

Just tried with the latest dev build of Ceylon IDE, and I don't get the same compiler error, but at least it seems the issue is partly fixed.
Issue here: 

William Draï

unread,
Apr 24, 2013, 6:37:19 PM4/24/13
to ceylon...@googlegroups.com
Well I feel I'm doing something wrong, but now everything compiles and I get a RuntimeException when running my example :

More or less the same class :
shared class ListenerHelper<Args>() given Args satisfies Anything[] {
variable Array<Callable<Anything, Args>> listeners = array<Callable<Anything, Args>>([]);
shared void addListener(Callable<Anything, Args> listener) {
if (listeners.contains(listener)) {
return;
}
Array<Callable<Anything, Args>> newListeners = arrayOfSize(listeners.size+1, listener);
if (listeners.size > 0) {
listeners.copyTo(newListeners, 0, 0, listeners.size);
}
listeners = newListeners;
}
shared void removeListener(Callable<Anything, Args> listener) {
variable Integer index = 0;
for (i->l in listeners.indexed) {
if (l == listener) {
index = i;
break;
}
}
Array<Callable<Anything, Args>> newListeners = arrayOfSize(listeners.size+1, listener);
if (index > 0) {
listeners.copyTo(newListeners, 0, 0, index);
}
if (index < listeners.size) {
listeners.copyTo(newListeners, index+1, index, listeners.size-index-1);
}
listeners = newListeners;
}
shared void fireEvent(Args args) {
for (listener in listeners) {
listener(args);
}
}
}

And the test :
void testListenerHelper() {

variable Boolean changed = false;

void listener(String prop) {
changed = true;
}
ListenerHelper<[String]> helper = ListenerHelper<[String]>(); 
helper.addListener(listener);
helper.fireEvent([ "Event" ]);
assert(changed == true);
}

When I run the test, I get this :
Exception in thread "main" java.lang.RuntimeException: java.lang.ClassCastException: ceylon.language.ArraySequence cannot be cast to ceylon.language.String
at com.redhat.ceylon.compiler.java.runtime.ide.Launcher.invokeMain(Launcher.java:86)
at com.redhat.ceylon.compiler.java.runtime.ide.Launcher.main(Launcher.java:53)
Caused by: java.lang.ClassCastException: ceylon.language.ArraySequence cannot be cast to ceylon.language.String
at org.granite.test.databinding.testListenerHelper_$1.$call(TestListenerHelper.ceylon:13)
at org.granite.databinding.ListenerHelper.fireEvent(ListenerHelper.ceylon:38)
at org.granite.test.databinding.testListenerHelper_.testListenerHelper(TestListenerHelper.ceylon:15)
at org.granite.test.databinding.testListenerHelper_.main(TestListenerHelper.ceylon)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)

What I understand from this is that fireEvent tries to call the listener with one single argument of type Array, when the listener expects a String.
In fact when seeing this, I don't even know how the runtime would know what to do :
shared void fireEvent(Args args) {
    for (listener in listeners) {
        listener(args);
    }
}

listener is a Callable<Anything, Args>, so I guess it should unpack the sequence or arguments and pass them to the callable.
However that feels wrong to me, why wouldn't it just pass the array as is as a single argument to the method ?

The problem is that everything compiles now and I really don't know if I'm doing something utterly stupid or if there is a bug somewhere.

I've also tried this just in case, but I got exactly the same error :
shared void fireEvent(Args args) {
for (listener in listeners) {
if (args.size == 0) {
listener();
}
else if (args.size == 1) {
listener(args[0]);
}
else if (args.size == 2) {
listener(args[0], args[1]);
}
else if (args.size == 3) {
listener(args[0], args[1], args[2]);
}
}
}

Tom Bentley

unread,
Apr 25, 2013, 4:15:22 AM4/25/13
to ceylon...@googlegroups.com

Just tried with the latest dev build of Ceylon IDE, and I don't get the same compiler error, but at least it seems the issue is partly fixed.
Issue here: 


Thanks for reporting that.

Tom

Stephane Epardaud

unread,
Apr 25, 2013, 4:25:14 AM4/25/13
to ceylon...@googlegroups.com
William, great to see you here!

I'll fix both your bugs today. The one you reported because it's trivial. The one you hit later because I also hit it yesterday ;)

So hang on.


--
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?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
Stéphane Épardaud

William Draï

unread,
Apr 25, 2013, 10:38:35 AM4/25/13
to ceylon...@googlegroups.com
Cool, thanks.

Stephane Epardaud

unread,
Apr 26, 2013, 12:01:44 PM4/26/13
to ceylon...@googlegroups.com
I've just pushed a new IDE on the DEV channel that fixes the first bug and a bug in unflatten, but not https://github.com/ceylon/ceylon-compiler/issues/1136 yet. You should use unflatten until we figure it out.

William Draï

unread,
Apr 29, 2013, 9:36:27 AM4/29/13
to ceylon...@googlegroups.com
Ok, I'll try it.

William Draï

unread,
Apr 30, 2013, 6:45:30 AM4/30/13
to ceylon...@googlegroups.com
Well, just checked and I confirm that the first bug (type alias) is fixed now.
Reply all
Reply to author
Forward
0 new messages