method overloading && inheritance prb

145 views
Skip to first unread message

Julien Viet

unread,
Jul 1, 2015, 5:36:34 AM7/1/15
to ceylo...@googlegroups.com
Hi,

I’ve started the work on the Ceylon code generator and one blocking issue I’m having is the support of method overloading combined with inheritance.

Method overloading alone can be achieved with default parameters, however combined with inheritance it raise problems.

Here is a simple example:

public class Foo {
  public void method(String s) {
  } 
}

public class Bar extends Foo {
  public void method(String s, Integer i) {
  }
  public void method(Integer i) {
  }
}

that can’t easily mapped in Ceylon for obvious reasons.

I’ve thought about various work around like renaming, replacing inheritance by delegation, but none of them seems to be great.

I welcome any genius idea :-)

-- 
Julien Viet
www.julienviet.com

Stephane Epardaud

unread,
Jul 1, 2015, 6:07:20 AM7/1/15
to ceylon-dev
What is the source of the generation? IDL? Java interfaces? Is is a wrapper you're generating? What does it call?

--
You received this message because you are subscribed to the Google Groups "ceylon-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ceylon-dev+...@googlegroups.com.
To post to this group, send email to ceylo...@googlegroups.com.
Visit this group at http://groups.google.com/group/ceylon-dev.
To view this discussion on the web visit https://groups.google.com/d/msgid/ceylon-dev/etPan.5593b49c.ded7263.11a%40juliens-mbp-2.
For more options, visit https://groups.google.com/d/optout.



--
Stéphane Épardaud

Gavin King

unread,
Jul 1, 2015, 6:36:56 AM7/1/15
to ceylo...@googlegroups.com
Well one solution would be to use a field of tupe Callable instead,
since we support covariant refinement of return types.

It's not perfect, since you lose some nice autocompletion in the IDE,
but it would *work*.
> --
> You received this message because you are subscribed to the Google Groups
> "ceylon-dev" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to ceylon-dev+...@googlegroups.com.
> To post to this group, send email to ceylo...@googlegroups.com.
> Visit this group at http://groups.google.com/group/ceylon-dev.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/ceylon-dev/etPan.5593b49c.ded7263.11a%40juliens-mbp-2.
> 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

Julien Viet

unread,
Jul 1, 2015, 9:07:03 AM7/1/15
to Gavin King, ceylo...@googlegroups.com
that’s quite genius idea actually and you saved my day :-)

shared abstract class Foo() {

  

  shared formal Anything(String) method;

  

}


shared class Bar() extends Foo() {

  

  void method_impl([String]|[String, Integer] args) {

    print("called with ``args``");

  }

  

  shared actual Anything(*<[String]|[String, Integer]>) method = flatten(method_impl);

}


Is there a more literal syntax than using flatten ?

-- 
Julien Viet
www.julienviet.com

Gavin King

unread,
Jul 1, 2015, 9:36:44 AM7/1/15
to Julien Viet, ceylo...@googlegroups.com
What's wrong with this:


shared class Bar() extends Foo() {
void method_impl(String s, Integer i=0) {}
shared actual Anything(String,Integer=) method = method_impl;

Julien Viet

unread,
Jul 1, 2015, 9:40:10 AM7/1/15
to Gavin King, ceylo...@googlegroups.com
so now let’s suppose that method is “fluent” and returns this, how can we make a work around the ref initializer leak ?

I’m trying to use the late annotation but without success.


-- 
Julien Viet
www.julienviet.com

Julien Viet

unread,
Jul 1, 2015, 9:50:04 AM7/1/15
to Gavin King, ceylo...@googlegroups.com
I believe the problem is that we cannot guarantee that cannot “order" the overloads, we can have any kind of overloading.

for instance in HttpServerResponse:

end();
end(Buffer data);
end(String chunk, String enc);
end(String chunk);

-- 
Julien Viet
www.julienviet.com

Julien Viet

unread,
Jul 2, 2015, 10:32:37 AM7/2/15
to Gavin King, ceylo...@googlegroups.com
Hi,

I created a repo here : https://github.com/vert-x3/vertx-lang-ceylon if you want to follow the dev

it contains generation of Vert.x core basic structure : types with method declarations based on Gavin’s suggestion and the code compiles to a Ceylon module.

I believe Gavin’s suggestion is (at least for now) the most appropriate way for getting an implementation that works in all cases.

Obviously the generated signatures can be optimized later (so Boolean(*<[]>) is rewritten to Boolean(), etc...)

The generated Ceylon basic struct for Vert.x core is located there : https://github.com/vert-x3/vertx-lang-ceylon/tree/initial-work/src/main/ceylon/io/vertx/ceylon/core

-- 
Julien Viet
www.julienviet.com

Gavin King

unread,
Jul 2, 2015, 12:19:56 PM7/2/15
to Julien Viet, ceylo...@googlegroups.com
This is for Vert.x 3, right?

Julien Viet

unread,
Jul 2, 2015, 12:29:31 PM7/2/15
to Gavin King, ceylo...@googlegroups.com
indeed.

-- 
Julien Viet
www.julienviet.com

Gavin King

unread,
Jul 2, 2015, 2:03:42 PM7/2/15
to Julien Viet, ceylo...@googlegroups.com
Cool :)

Tom Kaitchuck

unread,
Jul 2, 2015, 6:13:05 PM7/2/15
to ceylo...@googlegroups.com
Why not just have a single function that takes the args as a tuple and do a switch on the parameters, first thing. Then each function is just a block. This allows you to sill have strong typing, and still delegate to super.whatever() in one of the blocks if needed.

--

Julien Viet

unread,
Jul 3, 2015, 1:56:48 AM7/3/15
to Tom Kaitchuck, ceylo...@googlegroups.com
I’m not sure to understand, can you give a concrete example?

-- 
Julien Viet
www.julienviet.com

Julien Viet

unread,
Jul 6, 2015, 4:29:03 AM7/6/15
to Tom Kaitchuck, ceylo...@googlegroups.com
I’m working on the Vert.x @DataObject generation (javabean still like classes) and I’m getting into troubles for inheritance:

class Options(shared default String abc) {
}

class OptionsExt(shared actual default String abc) extends Options(abc) {
}

class OptionsExtExt(shared actual default String abc) extends OptionsExt(abc) {
}

error “Default member may not be used in initialized: abc”

what I’m doing seems like a fairly common pattern, does this error makes sense ?

-- 
Julien Viet
www.julienviet.com

Julien Viet

unread,
Jul 6, 2015, 5:10:20 AM7/6/15
to Tom Kaitchuck, ceylo...@googlegroups.com
made it works thanks to Tom, never mind :-)

-- 
Julien Viet
www.julienviet.com

Tako Schotanus

unread,
Jul 6, 2015, 6:36:08 AM7/6/15
to ceylon-dev
Just for documentation purposes in case anyone finds this thread in the future and wonders what the solution was:

    class Options(shared default String abc) {
    }

    class OptionsExt(String abc) extends Options(abc) {
    }

    class OptionsExtExt(String abc) extends OptionsExt(abc) {
    }


-Tako

John Vasileff

unread,
Jul 6, 2015, 11:14:37 AM7/6/15
to ceylo...@googlegroups.com
I was going to try to explore/demo a potential shadowing issue with this. But then I hit a compile error:

class Options(shared default String abc) {}

class OptionsExt(String abc) extends Options(abc) {}

class OptionsExtExt() extends OptionsExt("initial") {
    // May not inherit two declarations with the same name
    // that do not share a common supertype: abc is defined
    // by supertypes OptionsExtExt and Options
    shared actual variable String abc = "initial";
}

Is it right that this code is illegal? The `abc` in `OptionsExt` seems to be caught between being a value local to the initializer section and an attribute of the class.

The shadowing issue can be seen in the simpler example below that does compile, where `abc` in `OptionsExt` refers to the init parameter, not the class attribute:

class Options(shared default variable String abc) {}

class OptionsExt(String abc) extends Options(abc) {
    shared String oeABC => abc;
}

shared void testOEE() {
    value oe = OptionsExt("initial");
    oe.abc = "new";
    print(oe.abc);   // new
    print(oe.oeABC); // initial
}

So it may be safer to use constructors in the subclasses rather than initialization parameter lists.

Now, if we dig a bit deeper, the `abc` identifier in `OptionsExt` seems to act locally as if it refines (not shadows) `Options.abc` as can be seen when printing `oeABCThis`, but the "refinement" is hidden from subclasses, as can be seen when printing “oeeABCThis” and “oeeABCSuper”:

class Options(shared default variable String abc) {
}

class OptionsExt(String abc) extends Options(abc) {
    shared String oeABCThis => this.abc;
    shared String oeABCSuper => super.abc;
}

class OptionsExtExt(String x) extends OptionsExt(x) {
    shared String oeeABCThis => this.abc;
    shared String oeeABCSuper => super.abc;
}

shared void testOEE() {
    value oe = OptionsExtExt("initial");
    oe.abc = "new";
    print(oe.abc);         // new
    print(oe.oeABCThis);   // initial ???
    print(oe.oeABCSuper);  // new
    print(oe.oeeABCThis);  // new ???
    print(oe.oeeABCSuper); // new ???
}

So how exactly should `abc` in `OptionsExt`’s init parameter list be characterized? Should this identifier re-use even be allowed? If so, should `this.x` be clarified to mean the class attribute `x`, and not the newly introduced `x`? Polymorphism seems to be at odds with the block structure.

John

Julien Viet

unread,
Jul 6, 2015, 3:31:57 PM7/6/15
to ceylo...@googlegroups.com, John Vasileff

On 6 Jul 2015 at 17:14:38, John Vasileff (jo...@vasileff.com) wrote:

I was going to try to explore/demo a potential shadowing issue with this. But then I hit a compile error:

classOptions(shareddefault Stringabc) {}

classOptionsExt(Stringabc) extendsOptions(abc) {}

classOptionsExtExt() extendsOptionsExt("initial") {
    // May not inherit two declarations with the same name
    // that do not share a common supertype: abc is defined
    // by supertypes OptionsExtExt and Options
    shared actualvariable Stringabc = "initial";
}

Is it right that this code is illegal? The `abc` in `OptionsExt` seems to be caught between being a value local to the initializer section and an attribute of the class.

The shadowing issue can be seen in the simpler example below that does compile, where `abc` in `OptionsExt` refers to the init parameter, not the class attribute:

classOptions(shareddefault variableStringabc) {}

classOptionsExt(Stringabc) extendsOptions(abc) {
    shared String oeABC => abc;
}

sharedvoidtestOEE() {
    value oe = OptionsExt("initial");
    oe.abc = "new";
    print(oe.abc);   // new
    print(oe.oeABC); // initial
}

So it may be safer to use constructors in the subclasses rather than initialization parameter lists.

Now, if we dig a bit deeper, the `abc` identifier in `OptionsExt` seems to act locally as if it refines (not shadows) `Options.abc` as can be seen when printing `oeABCThis`, but the "refinement" is hidden from subclasses, as can be seen when printing “oeeABCThis” and “oeeABCSuper”:

classOptions(shareddefault variableStringabc) {
}

classOptionsExt(Stringabc) extendsOptions(abc) {
    shared String oeABCThis => this.abc;
    shared String oeABCSuper => super.abc;
}

classOptionsExtExt(Stringx) extendsOptionsExt(x) {
    shared String oeeABCThis => this.abc;
    shared String oeeABCSuper => super.abc;
}

sharedvoidtestOEE() {
    valueoe = OptionsExtExt("initial");

Stephane Epardaud

unread,
Jul 6, 2015, 4:55:36 PM7/6/15
to ceylon-dev
Scary signatures ;)


For more options, visit https://groups.google.com/d/optout.



--
Stéphane Épardaud

Gavin King

unread,
Jul 8, 2015, 8:31:28 PM7/8/15
to ceylo...@googlegroups.com

Julien Viet

unread,
Jul 10, 2015, 9:31:19 AM7/10/15
to Gavin King, ceylo...@googlegroups.com
the code generator supports fluent methods and generates something like:

  TestInterface fluentMethod_impl([String] args) {
    throw Exception("implement me");
  }

  shared  TestInterface(*<[String]>) fluentMethod = flatten(fluentMethod_impl);
  
normally implement me should be “return this”, however this leads to a reference leak in constructor.

of course fluentMethod_impl cannot be declared after fluentMethod otherwise it creates a forward reference.

is there a declaration that would make this possible ?

-- 
Julien Viet
www.julienviet.com

Julien Viet

unread,
Jul 10, 2015, 9:46:22 AM7/10/15
to Gavin King, ceylo...@googlegroups.com
I would rather like to avoid this kind of workaround:

shared class Foo() {
  shared Reference<Foo> ref = Reference<Foo>(null);
  shared Foo method_impl() {
    assert(exists a = ref.obj);
    return a;
  }
  shared Foo() method = method_impl;
}

Foo makeFoo() {
  Foo foo = Foo();
  foo.ref.obj = foo;
  return foo;
}

shared class Reference<T>(variable shared T? obj) {}

-- 
Julien Viet
www.julienviet.com

Julien Viet

unread,
Jul 10, 2015, 9:47:59 AM7/10/15
to Gavin King, ceylo...@googlegroups.com
actually no need for Reference:

shared class Foo() {

  shared variable Foo? ref = null;

  shared Foo method_impl() {

    assert(exists a = ref);

    return a;

  }

  shared Foo() method = method_impl;

}


Foo makeFoo() {

  Foo foo = Foo();

  foo.ref = foo;

  return foo;

}


that’s still ugly though

-- 
Julien Viet
www.julienviet.com

Lucas Werkmeister

unread,
Jul 10, 2015, 1:21:27 PM7/10/15
to ceylo...@googlegroups.com
I think it should work if you use `=>` instead of `=` when defining `fluentMethod`, at a slight performance cost.

Julien Viet

unread,
Jul 11, 2015, 2:01:36 AM7/11/15
to ceylo...@googlegroups.com
indeed it seems more happy, thanks for the tip :)


-- 
Julien Viet
www.julienviet.com

John Vasileff

unread,
Jul 11, 2015, 2:02:47 AM7/11/15
to ceylo...@googlegroups.com
You can recover most of the performance cost with a memo. Although I guess there could be a thread safety issue.

class TestC() {
    variable TestC(*<[String]>)? fluentMethodMemo = null;

    TestC fluentMethod_impl([String] args) {
        return this;
    }

    shared TestC(*<[String]>) fluentMethod
        =>  fluentMethodMemo else (fluentMethodMemo = flatten(fluentMethod_impl));
}

John

Julien Viet

unread,
Jul 11, 2015, 2:12:23 AM7/11/15
to ceylo...@googlegroups.com, John Vasileff
in this case, the potential race would not be a problem.

however it makes the generated source a bit more complicated to understand and I would like to have the simplest possible generation, so that could be used if there is a performance problem at some point.

-- 
Julien Viet
www.julienviet.com

On 11 Jul 2015 at 08:02:48, John Vasileff (jo...@vasileff.com) wrote:

You can recover most of the performance cost with a memo. Although I guess there could be a thread safety issue.

class TestC() {
    variableTestC(*<[String]>)? fluentMethodMemo = null;

    TestCfluentMethod_impl([String] args) {
        return this;
    }

    shared TestC(*<[String]>) fluentMethod
        =>  fluentMethodMemoelse (fluentMethodMemo = flatten(fluentMethod_impl));
}

Julien Viet

unread,
Jul 21, 2015, 4:31:01 PM7/21/15
to Gavin King, ceylo...@googlegroups.com
I think the downside of this approach is to lose method generic types, right ?

-- 
Julien Viet
Sent with Airmail

On 1 Jul 2015 at 12:36:56, Gavin King (gavin...@gmail.com) wrote:

Julien Viet

unread,
Jul 22, 2015, 4:26:03 AM7/22/15
to Gavin King, ceylo...@googlegroups.com
the main issue with lack of generics is that it makes not possible to make this kind of method in Vert.x work :

<T> void executeBlocking(Handler<Future<T>> blockingCodeHandler, Handler<AsyncResult<T>> resultHandler);

it would be only Object which limits the usability and force to use assert

-- 
Julien Viet
Sent with Airmail

Stephane Epardaud

unread,
Jul 22, 2015, 4:28:06 AM7/22/15
to ceylon-dev, Gavin King
Yes indeed that's a problem. Did you try annotating your source API with @Name annotations on overloaded methods so you could generate unique names and the mapping would then be easier?


For more options, visit https://groups.google.com/d/optout.



--
Stéphane Épardaud

Julien Viet

unread,
Jul 22, 2015, 6:13:28 AM7/22/15
to Stephane Epardaud, ceylo...@googlegroups.com, Gavin King
we don’t plan to add such @Name annotation in code generator because this always leads to clunky names, i.e writeString, writeBuffer, writeXXX 
-- 
Julien Viet
Sent with Airmail

Julien Viet

unread,
Jul 22, 2015, 6:28:52 AM7/22/15
to Stephane Epardaud, ceylo...@googlegroups.com, Gavin King
I’m wondering also why the following is not permitted:

class A() {

  shared default void foo(String s) {}

}


class B() extends A() {

  shared actual default void foo(String|Integer s) {}

}


that would make things easier
-- 
Julien Viet
Sent with Airmail

Lucas Werkmeister

unread,
Jul 22, 2015, 6:31:37 AM7/22/15
to ceylo...@googlegroups.com
Spec, 4.7.8:
Note: in a future release of the language, we would like to support contravariant refinement of method parameter types.
I assume it’s because the JVM doesn’t support it, so it would be difficult to do on the JVM backend.

Julien Viet

unread,
Jul 22, 2015, 6:34:43 AM7/22/15
to Stephane Epardaud, ceylo...@googlegroups.com, Gavin King
would it be feasible to generate Java sources instead of Ceylon but have this Java code work well with Ceylon types like functions, etc…

for instance we have Handler class in Vert.x that is more or less equivalent to a void function callback, used like:

public void close(Handler<Void> onClose);

so in Ceylon we need to invoke it in the wrapper or directly with:

shared void close(Callable<Anything, []> f) {
  object adapter implements Handler<Void> {
    shared void handle(Void v) {
      f();
    }
  }
  close(adapter);
}

so we would generate Java code that understands what a Ceylon Callable is and used could call it directly with Ceylon functions.

does it make sense ?

-- 
Julien Viet
Sent with Airmail

On 22 Jul 2015 at 10:28:07, Stephane Epardaud (stephane...@gmail.com) wrote:

John Vasileff

unread,
Jul 22, 2015, 10:25:22 AM7/22/15
to ceylo...@googlegroups.com
Yeah, and even on non-JVM platforms, it might rule out erasing to native types - B() would have to accept nativeString | String | Integer, and deal with the consequences.

Stephane Epardaud

unread,
Jul 22, 2015, 11:12:56 AM7/22/15
to Julien Viet, ceylon-dev, Gavin King
Well that's a very subjective argument. Ceylon's philosophy is indeed that you would use such names, so they're not clunky. You can try to turn Ceylon into what it's not, but given that you're having a lot of trouble that way, perhaps you should at least _try_ to make it in a way that works with Ceylon? Take a few interfaces, put these annotations, and try it. If it turns out to be a lot easier that way, then it's worth considering.
--
Stéphane Épardaud

Julien Viet

unread,
Jul 22, 2015, 2:10:43 PM7/22/15
to Stephane Epardaud, Gavin King, ceylon-dev
not, sure overloading is sometimes not namable easily :-), any the overloading problem can sometimes workaround with optional parameters.

However that does not solve the overloading / overriding problem that happens:

public interface WriteStream<T> {
   void write(T t);
}

public interface HttpServerResponse extends WriteStream<Buffer> {
  @Override
  void write(Buffer b);
  void write(String s);
}

in that case we should be able to have

void write(Buffer|String );

Unless I’m wrong, I don’t think that brakes the inheritance problem i;e an HttpServerResponse could still be casted as a WriteStream<Buffer> with no harm

Gavin’s idea to use function fields instead of methods was to solve this problem.

-- 
Julien Viet
Sent with Airmail

Julien Viet

unread,
Jul 22, 2015, 4:34:51 PM7/22/15
to Stephane Epardaud, Gavin King, ceylon-dev
better english : "anyWAY the overloading problem can sometimes BE workaroundED with optional parameters."
-- 
Julien Viet
Sent with Airmail

Stephane Epardaud

unread,
Jul 23, 2015, 3:45:39 AM7/23/15
to Julien Viet, Gavin King, ceylon-dev
Sure but it's trivial to differentiate those methods with optional parameters and those you want renamed, with annotations. In your example, I'd rename "write(String)" to "writeString(String)" for a start, and later if you validate that this fixes all your issues, you can work on an annotation that says to merge them, for example, and then dispatch.
--
Stéphane Épardaud

Julien Viet

unread,
Jul 23, 2015, 10:35:20 AM7/23/15
to Stephane Epardaud, Gavin King, ceylon-dev
sure, but if we do that I don’t think we would have annotations in Vert.x codebase directly it would rather be a configuration file for each project to be converted.

-- 
Julien Viet
www.julienviet.com

Julien Viet

unread,
Jul 23, 2015, 10:37:33 AM7/23/15
to Stephane Epardaud, Gavin King, ceylon-dev
that being said, I’m rather at a point today where I don’t see an obvious good solution and I feel rather not optimist to deliver something straightforward, the code generator will take time to develop and will be quite complex compared to other languages because it will handle many particular case.

-- 
Julien Viet
www.julienviet.com

Stephane Epardaud

unread,
Jul 23, 2015, 10:47:49 AM7/23/15
to Julien Viet, Gavin King, ceylon-dev
Well, sure, but for a proto it's easier to try with annotations. You can then validate if that fixes all your problems or not and if yes move them elsewhere if you want. I don't see which other problem you'd have.
--
Stéphane Épardaud

Julien Viet

unread,
Jul 29, 2015, 5:07:52 AM7/29/15
to Stephane Epardaud, Gavin King, ceylon-dev
so I think there may be a solution with the currently developed solution based on gavin’s idea using covariance/contravariance:

In case of a covariant parameter type like Message<T> then Message<T> is rewritten Message<Nothing> and the implementation does the adaptation:

shared class Message<out T>() {

  shared T msg => nothing;

}


shared void consumer(Anything(Message<Nothing>) handler) {}


void test1() {

  consumer((Message<String> msg) => print(msg));

}


in case of contravariance, the same with Object (or Anything):

shared class Future<in T>() {

  shared void complete(T val) {}

}


shared void resolve(Anything(Future<Object>) handler) {}


void test2() {

  resolve((Future<String> fut) => print(fut));

}



The generated wrapper would get the type of the handler and use reified generics to check the callback object can be casted to the handler and deliver it.

-- 
Julien Viet
www.julienviet.com

Stephane Epardaud

unread,
Jul 29, 2015, 5:16:55 AM7/29/15
to Julien Viet, Gavin King, ceylon-dev
I still think all these crazy hacks just to solve an uninspired name issue is nuts.
--
Stéphane Épardaud

Julien Viet

unread,
Jul 29, 2015, 6:33:10 AM7/29/15
to Stephane Epardaud, Gavin King, ceylon-dev
ahah yes, to be honest I would rather go with regular methods but no renaming.

renaming put the burden on the api developer to use yet another annotation, vertx already uses annotations for describing apis and I just don’t want to add another annotation to make the API more loaded.


-- 
Julien Viet
www.julienviet.com

Gavin King

unread,
Jul 29, 2015, 6:33:16 AM7/29/15
to Stephane Epardaud, Julien Viet, ceylon-dev
FTR I agree.

Julien Viet

unread,
Jul 29, 2015, 6:34:45 AM7/29/15
to Gavin King, Stephane Epardaud, ceylon-dev
how about the solution to generate java code that accepts Ceylon types ?

I’ve never got feedback on this solution.

-- 
Julien Viet
www.julienviet.com

Stephane Epardaud

unread,
Jul 29, 2015, 6:35:41 AM7/29/15
to Julien Viet, Gavin King, ceylon-dev
Have you even tried generating different names? That sounds so much like the best option that I don't understand why you're even contemplating all the rest.
--
Stéphane Épardaud

Julien Viet

unread,
Jul 29, 2015, 6:40:12 AM7/29/15
to Gavin King, Stephane Epardaud, ceylon-dev
my personal opinion is in both cases we are trying to find a solution for a problem that should not exist.

-- 
Julien Viet
www.julienviet.com


On 29 Jul 2015 at 12:33:16, Gavin King (gavin...@gmail.com) wrote:

Stephane Epardaud

unread,
Jul 29, 2015, 6:52:18 AM7/29/15
to Julien Viet, Gavin King, ceylon-dev
An my opinion is that your disagreeing with a fundamental "feature" of Ceylon (no overloading) led you to refuse to accept it and try to bypass it using more and more complex options that turn out way worse than "just" accepting to rename methods.

It's a bit like disagreeing with Java's type system and making your entire API use "Object" rather than proper types and rely on runtime checks to get it right. It may be necessary in some extreme cases, but only after you've tried the obvious easy solution.

Now, after you try to use proper method names, perhaps you'll hit another issue which will make it impossible to continue, but we haven't even explored that path yet, and it really sounds to me like the easiest/best way to start.
--
Stéphane Épardaud

Gavin King

unread,
Jul 29, 2015, 7:10:33 AM7/29/15
to Julien Viet, Stephane Epardaud, ceylon-dev
I mean seriously I would just generate disambiguating names
methodWithString(), methodWithStringAndInteger() etc.

Julien Viet

unread,
Jul 29, 2015, 7:11:29 AM7/29/15
to Stephane Epardaud, Gavin King, ceylon-dev
Don’t misundertand me, I mean that

in case of Ceylon running with Java native backend I am not shocked to use overloading since Java by nature provides overloading and actually interop would not work.

More over Ceylon code you can invoke Java code that provides overloaded method, right ?

I don’t think the code produced by the vertx generator is really Ceylon code, it’s code written in Ceylon that uses Java code and make adaptation on the types.

I don’t see why the vertx generator could not produce such class files that use ceylon types and use the natural overloading that Java provides: it would simply solve the problem.

At the end whether you use a Java class or a Ceylon declaration compiled for JVM backend, both are .class files.

-- 

Julien Viet

unread,
Jul 29, 2015, 7:16:02 AM7/29/15
to Gavin King, Stephane Epardaud, ceylon-dev
fine that’s what I'll do.

that being said it does not answer my question.

-- 
Julien Viet
www.julienviet.com

Gavin King

unread,
Jul 29, 2015, 7:18:00 AM7/29/15
to Julien Viet, Stephane Epardaud, ceylon-dev
Well the thing is that if you use overloading you lose functionality.
You can't take a function reference to an overloaded method.

Julien Viet

unread,
Jul 29, 2015, 7:24:49 AM7/29/15
to Gavin King, Stephane Epardaud, ceylon-dev
makes sense, is it still possible though ?

Gavin King

unread,
Jul 29, 2015, 7:32:03 AM7/29/15
to Julien Viet, Stephane Epardaud, ceylon-dev
Is what possible?

I mean, sure, in principle I can make it possible to define overloaded
methods in Ceylon, but:

1. We would need to define all the same nasty, broken rules that Java
has, e.g. that you can't have foo(List<Bar> list) and foo(List<Foo>
list). Ceylon does not currently feature any of this sort of broken
broken reasoning.
2. We would have to figure out how that maps to other platforms like
JS and Dart where overloading has no natural mapping.

These problems can be solved, certainly, but I would much prefer not
to solve them, since they complicate the language with wartiness and
lead programmers down the wrong path and into a trap. Overloading is
*bad* in a language with function refs, since I simply can't assign a
type to an overloaded method.

Overloading was even bad and broken in Java 5, where what was
allegedly a harmless implementation detail of generics (type erasure)
leaked into - and broke - the definition of method overloading.

So overloading is broken in Java, and Vert.x should not even be using it.

Julien Viet

unread,
Jul 29, 2015, 7:44:20 AM7/29/15
to Gavin King, Stephane Epardaud, ceylon-dev
no, actually I mean : generate a Java class source that interact well with Ceylon types, for instance

public class MyJavaType {
   public void callmeback(Function f) {
      f.call();
   }
}

that would be equivalent to

shared class MyCeylonType() {
  shared void callmeback(Anything() f) => f();
}

and provides overloading because Ceylon/Java interop allows invoking overloaded Java methods.

-- 
Julien Viet
www.julienviet.com

Gavin King

unread,
Jul 29, 2015, 7:47:38 AM7/29/15
to Julien Viet, Stephane Epardaud, ceylon-dev
And how's that better?

Julien Viet

unread,
Jul 29, 2015, 7:52:05 AM7/29/15
to Gavin King, Stephane Epardaud, ceylon-dev
JRuby provides a similar feature : you can create Java objects that are seen as Ruby objects and interact with Ruby types limiting the use of JRuby/Java interrop.

-- 
Julien Viet
www.julienviet.com

Gavin King

unread,
Jul 29, 2015, 7:57:55 AM7/29/15
to Julien Viet, Stephane Epardaud, ceylon-dev
I mean: sure, you can do it that way. But it seems much much worse
than just generating a disambiguating method name.

Lucas Werkmeister

unread,
Jul 29, 2015, 8:00:19 AM7/29/15
to ceylo...@googlegroups.com
But using a disambiguating method name means that all the documentation
for the affected methods is inaccurate, and looks a bit ugly since the
name suffixes have nothing to do with the _function_ of the method
(methodWithString() instead of methodWithStringUrl() for example).

Julien Viet

unread,
Jul 29, 2015, 8:06:06 AM7/29/15
to ceylo...@googlegroups.com
beyond documentation: tutorials, blog posts, screencasts, examples, etc…

-- 
Julien Viet
www.julienviet.com

--
You received this message because you are subscribed to the Google Groups "ceylon-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ceylon-dev+...@googlegroups.com.
To post to this group, send email to ceylo...@googlegroups.com.
Visit this group at http://groups.google.com/group/ceylon-dev.
Reply all
Reply to author
Forward
0 new messages