www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Ceylon language

reply bearophile <bearophileHUGS lycos.com> writes:
The first description of the Ceylon language, designed for business computing
(for large teams developing multi-user applications) and meant to replace Java,
from Red Hat, that will run on the Java Virtual Machine itself:
http://blog.talawah.net/2011/04/gavin-king-unviels-red-hats-top-secret.html

About the language (very slow download):
http://www.qconbeijing.com/download/Gavin%20keynote.pdf
About the its type system:
http://www.qconbeijing.com/download/Gavin%20session.pdf


Some of the Java things they are frustrated by:
- non-typesafety of null values
- the dangerous synchronized keyword
- clumsy annotation syntax
- verbose constructor syntax
- all Java objects are semaphores?!
- SE SDK overuses stateful (mutable) objects


The following parts are from the PDF documents, plus few comments of mine.

-------------

Ceylon does not support method overloading (or any other kind of overloading).

-------------

If a value of type T can be null, it must be declared as type Optional<T>,
which may be abbreviated to T?  

String? name = process.args.first;
if (exists name) {
    writeLine("Hello " name "!");
}
else {
    writeLine("Hello World!");
}

Use of an optional value must be guarded by the if (exists ... ) construct.
Therefore, NullPointerExceptions are impossible.

This is exactly what I suggested for D in a enhancement request.
It seems this kind of stuff is becoming a standard in new languages. 

-------------

Attributes and local variables are immutable by default. Assignable values must
be annotated variable:

variable Natural count := 0;

-------------

A getter looks like a method without a parameter list:

shared Natural currentValue { 
        return count; 
    }
}


Attributes are polymorphic. A subclass may override a superclass attribute. It
may even override a simple attribute with a getter or vice versa!

This means there is no need for explicit getter/setters until you are ready for
them. This is nice.

-------------

There is no new keyword:

Counter c = Counter();

-------------


The local keyword may be used in place of a type for block-local declarations:

local c = Counter();

-------------

Assignment to a variable value or attribute setter is done using the :=
operator. The = specifier is used only for specifying immutable values:

shared assign currentValue {
    count := currentValue;
}

-------------

We may define a class method "by reference":

void hello(String name) = hello;

-------------

A method may declare multiple lists of parameters. The method body is executed
after arguments have been supplied to all parameter lists:

Float add(Float x)(Float y) {
    return x+y;
}

This is a kind of user defined and safe partial application, it's a cute idea.

Providing arguments to just one parameter list produces a method reference:

Float addOne(Float y) = add(1.0);
Float three = addOne(2.0);

(The point of all this is that we are able to provide all the functionality of
first-class and higher-order functions without needing to resort to unnatural
syntactic constructs inspired by the lambda calculus notation.)

-------------

There is a Named argument syntax. They use it for a syntax trick: A named
argument invocation is enclosed in braces, and non-vararg arguments are listed
using the name=value; syntax.

This seems one of the most peculiar and refined parts of the syntax of this
language. See slides 34-37 in the first PDF.

-------------

A class or interface satisfies zero or more interfaces

shared class Character(Natural utf16) 
    extends Object()
    satisfies Ordinal & Comparable<Character> {
        ...
}

The syntax X&Y represents the intersection of two types. The syntax X|Y
represents the union of two types.

-------------

The "actual" annotation specifies that a member refines a supertype member:

shared class Character(Natural utf16) 
        extends Object()
        satisfies Ordinal & Comparable<Character> {
        
    Natural nat = utf16;

    shared actual Comparison compare(T that) {
        return this.nat <=> that.nat;
    }


The <=> operator is called "compare". It's just a shortcut for the method
compare() of Comparable.

-------------

Type narrowing, "Switching" by type

Type narrowing is often frowned upon in object-oriented programming

Unfortunately, Java exacerbates the problem:
- the compiler does not inform us when addition of a new subtype breaks the
list of cases


Node<String> node = ... ;
switch (node)
case (is Leaf<String>) { 
    leaf(node.value); 
}
case (is Branch<String>) { 
    branch(node.left, node.right); 
}
else {
    somethingElse(node);
}

The compiler forces the switch statement to contain an else clause to handle
other subtypes.

-------------

Enumerated subtypes

A class or interface may specify an explicitly enumerated list of subtypes. The
functional programming community calls this an algebraic datatype:

abstract class Node<T>(String name) 
       of Branch<T> | Leaf<T> { ... }

lass Leaf<T>(String name, T value) 
       extends Node<T>(name) { ... }

lass Branch<T>(String name, Node<T> left, Node<T> right
       extends Node<T>(name) { ... }


The compiler validates that switch statements contain either an exhaustive list
of possible subtypes or an else clause:

Node<String> node = ... ;
switch (node)
case (is Leaf<String>) { 
    leaf(node.value); 
}
case (is Branch<String>) { 
    branch(node.left, node.right); 
}

-------------

A type may be covariant or contravariant in its type parameter. (Respectively
in or out.):

interface WeakReferenceGetter<out T> { 
    shared formal T? get(T t); // Compile error: not covariant
}
interface WeakReferenceSetter<in T> { 
    shared formal T set(T t); // Compile error: not contravariant
}

The compiler validates member signatures to check that the type really does
respect the declared variance. This is way easier to understand than wildcard
types in Java.


Collections and variance:
- An interface like List<T> should be covariant in T since we almost always
want a List<String> to be a List<Object>
- Therefore, we need to split operations which mutate the list to a separate
interface OpenList<T>

-------------

Bye,
bearophile
Apr 13 2011
next sibling parent reply Kagamin <spam here.lot> writes:
bearophile Wrote:

 String? name = process.args.first;
 if (exists name) {
     writeLine("Hello " name "!");
 }
 else {
     writeLine("Hello World!");
 }
 
 Use of an optional value must be guarded by the if (exists ... ) construct.
Therefore, NullPointerExceptions are impossible.
 
How will it work on this code? String? name = process.args.first; myLibCustomEnforce(exists name); writeLine("Hello " name "!");
 A class or interface satisfies zero or more interfaces
 
 shared class Character(Natural utf16) 
     extends Object()
     satisfies Ordinal & Comparable<Character> {
         ...
 }
 
 The syntax X&Y represents the intersection of two types. The syntax X|Y
represents the union of two types.
 
What does it mean?
 Node<String> node = ... ;
 switch (node)
 case (is Leaf<String>) { 
     leaf(node.value); 
 }
 case (is Branch<String>) { 
     branch(node.left, node.right); 
 }
 else {
     somethingElse(node);
 }
Haha, finally properly scoped switch statement, but it goes java too much. Braces are required?
Apr 13 2011
parent reply bearophile <bearophileHUGS lycos.com> writes:
Kagamin:

 How will it work on this code?
 
 String? name = process.args.first;
 myLibCustomEnforce(exists name);
 writeLine("Hello " name "!");
If you want to implement the feature well, then the compiler has to manage a bit of type state too. The state of the type of the (here immutable) variable "name" before myLibCustomEnforce() is different from the state of the type of "name" after that call.
 shared class Character(Natural utf16)
     extends Object()
     satisfies Ordinal & Comparable<Character> {
         ...
 }

 The syntax X&Y represents the intersection of two types. The syntax X|Y
represents the union of two types.
What does it mean?
Those Ordinal and Comparable<Character> seem interfaces, and each of them has a certain number of methods. If you use Ordinal | Comparable<Character> I persume the Character class must implement the methods of both interfaces (as in D), while with "&" you need to implement just the methods present in both interfaces. I don't have enough experience about this to tell how much useful this feature is. But it's not at the top of the things I look for.
 Haha, finally properly scoped switch statement, but it goes java too much.
Braces are required?
Ceylon is meant to be a very regular and safe language designed for not expert programmers too, so I presume they are required here. Bye, bearophile
Apr 13 2011
next sibling parent Kagamin <spam here.lot> writes:
bearophile Wrote:

 How will it work on this code?
 
 String? name = process.args.first;
 myLibCustomEnforce(exists name);
 writeLine("Hello " name "!");
If you want to implement the feature well, then the compiler has to manage a bit of type state too. The state of the type of the (here immutable) variable "name" before myLibCustomEnforce() is different from the state of the type of "name" after that call.
Do you describe, how Ceylon can work hypotetically or how it actually works?
Apr 13 2011
prev sibling parent spir <denis.spir gmail.com> writes:
On 04/13/2011 07:06 PM, bearophile wrote:
 Kagamin:

  How will it work on this code?

  String? name = process.args.first;
  myLibCustomEnforce(exists name);
  writeLine("Hello " name "!");
If you want to implement the feature well, then the compiler has to manage a bit of type state too. The state of the type of the (here immutable) variable "name" before myLibCustomEnforce() is different from the state of the type of "name" after that call.
Yo; and while you're at "typestating", extend the feature to any type (not only pointers). Denis -- _________________ vita es estrany spir.wikidot.com
Apr 14 2011
prev sibling next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"bearophile" <bearophileHUGS lycos.com> wrote in message 
news:io458e$elr$1 digitalmars.com...
 Ceylon does not support method overloading (or any other kind of 
 overloading).
Eewww. Haxe is like that and it's nothing but a royal pain in the ass.
 If a value of type T can be null, it must be declared as type Optional<T>, 
 which may be abbreviated to T?

 String? name = process.args.first;
 if (exists name) {
    writeLine("Hello " name "!");
 }
 else {
    writeLine("Hello World!");
 }

 Use of an optional value must be guarded by the if (exists ... ) 
 construct. Therefore, NullPointerExceptions are impossible.

 This is exactly what I suggested for D in a enhancement request.
 It seems this kind of stuff is becoming a standard in new languages.
Yes, I'd *love* to see that in D, too.
 A method may declare multiple lists of parameters. The method body is 
 executed after arguments have been supplied to all parameter lists:

 Float add(Float x)(Float y) {
    return x+y;
 }

 This is a kind of user defined and safe partial application, it's a cute 
 idea.

 Providing arguments to just one parameter list produces a method 
 reference:

 Float addOne(Float y) = add(1.0);
 Float three = addOne(2.0);

 (The point of all this is that we are able to provide all the 
 functionality of first-class and higher-order functions without needing to 
 resort to unnatural syntactic constructs inspired by the lambda calculus 
 notation.)
That really stikes me as a completly wrong way to do currying. Granted, I've never really used currying, but it seems it would only be appropriate for *outside* code to choose which to specify and not specify. Having the callee decide that seems to completely defeat the whole point. Although I guess it could be sometimes be useful as a really ugly hack to work around the lack of overloading.
Apr 13 2011
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 4/13/11 3:03 PM, Nick Sabalausky wrote:
 "bearophile"<bearophileHUGS lycos.com>  wrote in message
 news:io458e$elr$1 digitalmars.com...
 Ceylon does not support method overloading (or any other kind of
 overloading).
Eewww. Haxe is like that and it's nothing but a royal pain in the ass.
 If a value of type T can be null, it must be declared as type Optional<T>,
 which may be abbreviated to T?

 String? name = process.args.first;
 if (exists name) {
     writeLine("Hello " name "!");
 }
 else {
     writeLine("Hello World!");
 }

 Use of an optional value must be guarded by the if (exists ... )
 construct. Therefore, NullPointerExceptions are impossible.

 This is exactly what I suggested for D in a enhancement request.
 It seems this kind of stuff is becoming a standard in new languages.
Yes, I'd *love* to see that in D, too.
I think you'd be hasty. As Kagamin mentioned, this ad-hoc guarding works straight against modularity. Also, without more details I can't really say, but if the type of the checked variable doesn't automagically change from T? to T inside the guarded code, a lot of subsequent uses (pass down to functions etc.) would have to repeat the check. Also, if the variable is reassigned it would have to change back the type from T to T?, which makes program understanding by both human and compiler (e.g. "do I need a test here?") a bitch. I'm highly skeptical of this feature in particular. I'm even more so because it's the kind of ad-hoc feature with many fuzzy corners that needs solid real-world validation, which... ("You can’t write code in the language just yet!") doesn't exist. Andrei
Apr 13 2011
parent reply bearophile <bearophileHUGS lycos.com> writes:
Kagamin:

 Do you describe, how Ceylon can work hypotetically or how it actually works?
There is no Ceylon implementation yet, and even its authors probably will have to change some of their ideas during the implementation phase, so there is not much real about what I have written. I have just interpreted the first documents they have released. Sorry for not being sufficiently explicit about this. (From what I've seen in the development of Scala, the Java VM allows to create a first language implementation in a not so much time.) --------------------- Nick Sabalausky:
That really stikes me as a completly wrong way to do currying. Granted, I've
never really used currying, but it seems it would only be appropriate for
*outside* code to choose which to specify and not specify.<
Here we are talking about a special case of partial function application, it's not currying. I have used partial application in Haskell, and it's very nice and very handy. If you have a function foo(x,y), in Haskell you are able to write things like: map (foo 5) somelist foo5 = foo 5 map foo5 somelist map (5 +) [0 .. 10] Partial application is nice for template arguments too. This is a little Rosettacode task to use partial application: http://rosettacode.org/wiki/Partial_function_application The Task: - Create a function fs( f, s ) that takes a function, f( n ), of one value and a sequence of values s. - Function fs should return an ordered sequence of the result of applying function f to every value of s in turn. - Create function f1 that takes a value and retuns it multiplied by 2. - Create function f2 that takes a value and returns it squared. - Partially apply f1 to fs to form function fsf1( s ) - Partially apply f2 to fs to form function fsf2( s ) -Test fsf1 and fsf2 by evaluating them with s being the sequence of integers from 0 to 3 inclusive and then the sequence of even integers from 2 to 8 inclusive. The Haskell version is very very simple: fs f s = map f s f1 value = value * 2 f2 value = value ^ 2 fsf1 = fs f1 fsf2 = fs f2 main = do print $ fsf1 [0, 1, 2, 3] print $ fsf2 [0, 1, 2, 3] print $ fsf1 [2, 4, 6, 8] print $ fsf2 [2, 4, 6, 8] D has a partial applicator in std.functional, but I think it can't be used here, this is a not so good implementation: import std.stdio, std.algorithm, std.range; template fs(alias f) { auto fs(Range)(Range s) { return map!f(s); } } auto f1(T)(T x) { return x * 2; } auto f2(T)(T x) { return x * x; } void main() { alias fs!f1 fsf1; alias fs!f2 fsf2; auto d1 = iota(0, 4); writeln(fsf1(d1)); writeln(fsf2(d1)); auto d2 = iota(2, 9, 2); writeln(fsf1(d2)); writeln(fsf2(d2)); } The problems I see with unrestricted partial application as in Haskell are: - I see this feature as possible source of bugs. If you don't give all arguments you generate a function instead of a result. I am not sure of this. - In some situations it's not immediately easy to understand code and what it is doing. Ceylon is targeted to commercial applications, and they are clearly trying to design a simple language, much simpler than Haskell and simpler than D too. So I presume they have found a compromise between "wild" Haskell-style partial application and no partial application at all as in C/C++/Java. They let the person that write the function to define what partial applications are allowed. This explicit design is how some higher order functions in Phobos are designed. map!(to!string)([1, 2, 3]) works thanks to nested templates, this is a way to manually specify what partial application there is in the template arguments. I don't know if this Ceylon design is good, but it looks like an interesting idea that I have not seen before. ---------------------- Andrei:
Also, without more details I can't really say, but if the type of the checked
variable doesn't automagically change from T? to T inside the guarded code, a
lot of subsequent uses (pass down to functions etc.) would have to repeat the
check. Also, if the variable is reassigned it would have to change back the
type from T to T?, which makes program understanding by both human and compiler
(e.g. "do I need a test here?") a bitch.<
I agree it's just a high level discussion, there are not enough details yet. It seems several new languages want to solve this problem. How and how well is to be seen. Bye, bearophile
Apr 13 2011
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
 template fs(alias f) {
     auto fs(Range)(Range s) {
         return map!f(s);
     }
 }
And by the way, this is similar to the "manual" partial application of Ceylon, just with a worse syntax. Bye, bearophile
Apr 13 2011
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 4/13/2011 2:14 PM, bearophile wrote:
 I agree it's just a high level discussion, there are not enough details yet.

 Rust. It seems several new languages want to solve this problem. How and how
 well is to be seen.
a language with lofty goals that doesn't actually work and doesn't seem to have that it is valid and useful.
Apr 13 2011
prev sibling next sibling parent reply spir <denis.spir gmail.com> writes:
On 04/13/2011 02:34 PM, bearophile wrote:

 -------------

 Ceylon does not support method overloading (or any other kind of overloading).
How to survive? Named args and default values somewhat mitigate this lack, but still... I read (somewhere) this only for /operator/ overloading.
 -------------

 If a value of type T can be null, it must be declared as type Optional<T>,
which may be abbreviated to T?

 String? name = process.args.first;
 if (exists name) {
      writeLine("Hello " name "!");
 }
 else {
      writeLine("Hello World!");
 }

 Use of an optional value must be guarded by the if (exists ... ) construct.
Therefore, NullPointerExceptions are impossible.

 This is exactly what I suggested for D in a enhancement request.
 It seems this kind of stuff is becoming a standard in new languages.
+++ But I guess optionality could, and should, extend to non-ref types; thus, null is just a particular case of non-existence. And this would apply especially on function parameters: void f (int i?) {...} Also, they should reuse '?' to mean 'exists', possibly '!?' meaning the opposite: void f (int i?) { if (? i) doWithI(i); if (!? i) doWithoutI(); ... }
 -------------

 Attributes and local variables are immutable by default. Assignable values
must be annotated variable:

 variable Natural count := 0;
Immutability should be the default for locals (especialy params) in all languages. 'Natural' is great ;-)
 -------------

 A getter looks like a method without a parameter list:

 shared Natural currentValue {
          return count;
      }
 }
good
 Attributes are polymorphic. A subclass may override a superclass attribute. It
may even override a simple attribute with a getter or vice versa!

 This means there is no need for explicit getter/setters until you are ready
for them. This is nice.
very good I often miss this in D. The fact that subtyping in D applies only to methods forces to add fake data members in supertypes (which are thus present in all subtypes...). I find this design crazy !!! Same note for mixins: why do they hold only methods? A "role" to be mixed-in often requires both data & methods.
 -------------

 There is no new keyword:

 Counter c = Counter();
great! get rid of new in D as well coll = (new Coll(cap)).fill(data); ==> coll = Coll(cap).fill(data);
 -------------

 Assignment to a variable value or attribute setter is done using the :=
operator. The = specifier is used only for specifying immutable values:

 shared assign currentValue {
      count := currentValue;
 }
If I understand you correctly, this is wrong. The operators should instead make distinct *creation* versus *change*: variable Natural count = 0; // create count := 3; // change local Natural i = 1; // cannot be changed
 -------------

 We may define a class method "by reference":

 void hello(String name) = hello;
???
 -------------

 A method may declare multiple lists of parameters. The method body is executed
after arguments have been supplied to all parameter lists:

 Float add(Float x)(Float y) {
      return x+y;
 }

 This is a kind of user defined and safe partial application, it's a cute idea.

 Providing arguments to just one parameter list produces a method reference:

 Float addOne(Float y) = add(1.0);
 Float three = addOne(2.0);

 (The point of all this is that we are able to provide all the functionality of
first-class and higher-order functions without needing to resort to unnatural
syntactic constructs inspired by the lambda calculus notation.)
I don't get the diff between currying & partial app. And find this feature much complication for close to uselessness.
 -------------

 There is a Named argument syntax.
A true programmer uses named args in half of all method calls; meaning, everywhere args' meanings are not absolutely obvious.
  They use it for a syntax trick: A named argument invocation is enclosed in 
braces, and non-vararg arguments are listed using the name=value; syntax.
 This seems one of the most peculiar and refined parts of the syntax of this
language. See slides 34-37 in the first PDF.
examples?
 -------------

 A class or interface satisfies zero or more interfaces

 shared class Character(Natural utf16)
      extends Object()
      satisfies Ordinal&  Comparable<Character>  {
          ...
 }

 The syntax X&Y represents the intersection of two types. The syntax X|Y
represents the union of two types.
Too bad, they got it wrong, like D. Should instead rip Go interfaces, which are structural & implicite, while still fully compile-time type-safe: struct File inStream { ... void write (string s) {...}; } ... interface Writer { void write (string s); } File is *also* a Writer, thus one can call the following on a specimen of File: void formatWrite (Writer w, string s, string format) {...} More generally, any type can satisfy any number of interfaces, wherever and whenever they are defined (eg years after, in user code). The obligation of explicitely declaring interface satisfaction is both useless and blocking. Free interfaces even provide some kind of simple generics for free (like in above example). And there is no need for ... if (is(...)) or ... if (isWriter!T) =========================================== All in all, Ceylon looks like a very good imrovement. Too bad its base for imrovement is Java (there is no way to get light & flexible coding from there, you'd have to change everything ;-), and it's designed to run on the JVM. :-( Denis -- _________________ vita es estrany spir.wikidot.com
Apr 14 2011
parent reply "Nick Sabalausky" <a a.a> writes:
"spir" <denis.spir gmail.com> wrote in message 
news:mailman.3497.1302788057.4748.digitalmars-d puremagic.com...
 On 04/13/2011 02:34 PM, bearophile wrote:

 If a value of type T can be null, it must be declared as type 
 Optional<T>, which may be abbreviated to T?

 String? name = process.args.first;
 if (exists name) {
      writeLine("Hello " name "!");
 }
 else {
      writeLine("Hello World!");
 }

 Use of an optional value must be guarded by the if (exists ... ) 
 construct. Therefore, NullPointerExceptions are impossible.

 This is exactly what I suggested for D in a enhancement request.
 It seems this kind of stuff is becoming a standard in new languages.
+++ But I guess optionality could, and should, extend to non-ref types; thus, null is just a particular case of non-existence. And this would apply especially on function parameters: void f (int i?) {...}
Oh absolutely. Haxe has nullable-primatives which really comes in handly at times (it often prevents the need for a separate bool to keep track of). Only problem is that in Haxe, not only is nullable the default, but it doesn't even *have* any non-nullables at all, for any type.
 I don't get the diff between currying & partial app. And find this feature 
 much complication for close to uselessness.
I'm not certain either, but I *think* partial application is just like currying except there's some sort of arbitrary limitaion on what combination(s) of paramaters you can choose to specify or not specify. And that limitation is based purely on what order the function defines its parameters. So basically, my understanding is that partial application is an arbitrarily-gimped currying.
 A class or interface satisfies zero or more interfaces

 shared class Character(Natural utf16)
      extends Object()
      satisfies Ordinal&  Comparable<Character>  {
          ...
 }

 The syntax X&Y represents the intersection of two types. The syntax X|Y 
 represents the union of two types.
Too bad, they got it wrong, like D. Should instead rip Go interfaces, which are structural & implicite, while still fully compile-time type-safe: struct File inStream { ... void write (string s) {...}; } ... interface Writer { void write (string s); } File is *also* a Writer, thus one can call the following on a specimen of File: void formatWrite (Writer w, string s, string format) {...} More generally, any type can satisfy any number of interfaces, wherever and whenever they are defined (eg years after, in user code). The obligation of explicitely declaring interface satisfaction is both useless and blocking. Free interfaces even provide some kind of simple generics for free (like in above example). And there is no need for ... if (is(...)) or ... if (isWriter!T)
I think Go's implicit interfaces are horrible. It's literally nothing more than duck-typing at compile time (ie, static duck-typing) and fully inherits duck-typing's downfalls (notably that it's sloppy and conflates name/signature with semantics - which is an entirely false connection). Of course, I guess this argument doesn't hold if you're a duck-typing fan ;)
 Too bad its base for imrovement is Java (there is no way to get light & 
 flexible coding from there, you'd have to change everything ;-),
Yup. This is one of the reasons I don't buy the claims of "Java's fast now, really!". In fact, the article I'm [trying to] write for the article competition relates to this. Basically, code can't be fast *and* flexible *and* maintable without real metaprogramming (and class-based generics don't count), and Java AFAIK just doesn't have metaprogramming. Although I suppose you might be able to hack it by using a pre-processor, but pre-processors have their downsides. And even if you did use one, Java's requirement that every aggregate type be a class can be a real hinderance. Of course, the JVM's advanced class/object optimizations may be able to help - but only to a point, and you still can't reliably prevent situations that would hinder the JVM's ability to do the necessary optimizations.
Apr 14 2011
next sibling parent reply Pelle <pelle.mansson gmail.com> writes:
On 04/15/2011 03:23 AM, Nick Sabalausky wrote:
 I'm not certain either, but I *think* partial application is just like
 currying except there's some sort of arbitrary limitaion on what
 combination(s) of paramaters you can choose to specify or not specify. And
 that limitation is based purely on what order the function defines its
 parameters. So basically, my understanding is that partial application is an
 arbitrarily-gimped currying.
In my understanding they are, while related, distinct like so: int foo(int x, int y, int z); int delegate(int, int) p = partiallyApply(&foo, 3); int delegate(int) delegate(int) delegate(int) c = curry(&foo); assert (p(4,5) == foo(3,4,5)); assert (c(3)(4)(5) == foo(3,4,5));
Apr 15 2011
parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
I've recently made an attempt to make a curry alternative which can
take any number of parameters (currently the curry implementation only
works with 1 parameter). I've put my implementation in bugzilla, it is
extremely simple (and maybe buggy :p)
http://d.puremagic.com/issues/show_bug.cgi?id=5829.

I've also tried to create a some sort of 'bind' function which could
let you bind arguments to specific parameters of a function. If I had
it working it would really help (me) out in coding for  e.g. the
Windows API. For example you might have a WinAPI function such as (I'm
pseudocoding here):

CreateWindow(int x, int y, int w, int h, int* opt1, int* opt2, int*
opt3, char* name);

And if you want to create a certain type of window with some
parameters which are always the same, you could create an alias that
binds certain arguments to this function:

alias bind!CreateWindow(void, void, width, height, null, null, null,
void) myWindow;

Here 'void' would designate arguments that you would have to fill in
when calling myWindow.

You would call it like:
myWindow(posX, posY, "MyWindowName");

which would translate the call to:
CreateWindow(posX, posY, width, height, null, null, null, "MyWindowName");

WinAPI is full of functions which take optional parameters which need
to be set to null if they're not to be used, so this kind of 'bind'
function could be pretty useful. But I've had zero luck with CTFE and
templates. Perhaps Don's upcoming CTFE revamp could make this
possible.
Apr 15 2011
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrej Mitrovic:

 alias bind!CreateWindow(void, void, width, height, null, null, null,
 void) myWindow;
How do you give a void argument to a function, in D2? This doesn't work, despite having templated void arguments seems potentially useful: void foo(T)(T x) {} void bar() {} void main() { foo(bar()); }
 But I've had zero luck with CTFE and
 templates. Perhaps Don's upcoming CTFE revamp could make this
 possible.
Don has changed mostly how CT functions manage their memory. Bye, bearophile
Apr 15 2011
next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
Here's a hardcoded example:

http://codepad.org/klr8S1hi

I've tried numerous ways of automatically creating the appropriate
call to fun in the bind template, but I've been unsuccessful. Maybe
using some form of string mixin would work.. My biggest issue is that
I can't modify variables at compile time. I wish there was some
special CTFE int type which is only visible at compile-time and which
we can use however we want. That way I could keep count of things, for
example I could generate a list of indexes that can then be mixed in
as a string.
Apr 15 2011
parent David Nadlinger <see klickverbot.at> writes:
On 4/15/11 8:19 PM, Andrej Mitrovic wrote:
 […] My biggest issue is that
 I can't modify variables at compile time. I wish there was some
 special CTFE int type which is only visible at compile-time and which
 we can use however we want. That way I could keep count of things, for
 example I could generate a list of indexes that can then be mixed in
 as a string.
 […]
 I dunno, CTFE overall seems like a buggy thing where I have to guesswhether
something will work or not. It's very stress-inducing.
Correct me if I'm wrong, but might it be that you are conflating templates and CTFE, which are – although they are both used for metaprogramming – two entirely different concepts? Maybe it helps to think of calling a function at compile time as a gate into a parallel universe. In this other world, you can modify variables, call functions, etc. as you please, just as if you were executing code at runtime (well, inside the more or less implementation-defined boundaries of CTFE). The only restriction is that you can only return a single value through the gate, there is no other way to influence the »compiler« universe from inside the functions you call. More specifically, there is no way to manipulate types in the compiler universe – although you can instantiate templates in CTFE functions just like normal, you will never be able to »return« them back to the outside world. Also, be aware of the fact that a CTFE function can just work on _values_, like every other runtime function, not on types. So much for CTFE. Templates, on the other hand, are basically just named scopes with a few extra features which happen to make a Turing complete language. As such, there will never be something like a runtime variable modifiable at compile time in templates, as you asked (at least I hope so). The interesting thing about templates is that they allow you to work with types themselves. Due to the absence of mutable state, you are generally limited to functional techniques, though, which can be uncomfortably similar to the proverbial Turing tarpit in some cases (although it's surprising how easy it is to write certain algorithms in a functional manner once you got the hang of it). However, there are ways to combine templates and CTFE to your advantage. Without any concrete question, it's obviously hard to give a good suggestion, but an example would be to use template functions called at compile time to produce string mixins: --- string generateCode(T...)() { string code; [… construct a string containing some declarations …] return code; } template Foo(T...) { alias DoSomethingWithATypeTuple!(T) U; mixin(generateCode(U)); } --- You can also shorten this by using delegate literals: --- template Foo(T...) { alias DoSomethingWithATypeTuple!(T) U; mixin({ […] return "<some code generated while having access to T and U>"; }()); } --- Another small template metaprogramming example showing a way to process a list of types without needing mutable state. Specifically, it aliases a new type tuple to Result which doesn't contain any items where Exp.numerator is 0 (you can do the same with eponymous templates). TypeTuples are automatically flattened, which allows for a concise implementation here. --- template Process(T...) { static if (T.length == 0) { alias TypeTuple!() Result; } else { alias T[0] A; static if (A.Exp.numerator == 0) { alias Process!(T[1..$]).Result Result; } else { alias TypeTuple!(A, Process!(T[1..$]).Result) Result; } } } --- As for constructing lists of indices and then generating code of them: If you need to work on types for generating the list, you could e.g. use some recursive template to construct a type tuple of integer literals (that name really doesn't fit well), and then process it via CTFE to generate code to be mixed in – or whatever you need in your specific case. Feel free to ask about any specific problems in d.D.learn. David
Apr 16 2011
prev sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
Oh and the reason I used a struct and opCall inside the template is
because this somehow allowed me to use foreach for some things. I
dunno, CTFE overall seems like a buggy thing where I have to guess
whether something will work or not. It's very stress-inducing.
Apr 15 2011
prev sibling parent reply KennyTM~ <kennytm gmail.com> writes:
On Apr 16, 11 00:29, Andrej Mitrovic wrote:
 I've also tried to create a some sort of 'bind' function which could
 let you bind arguments to specific parameters of a function. If I had
 it working it would really help (me) out in coding for  e.g. the
 Windows API. For example you might have a WinAPI function such as (I'm
 pseudocoding here):

 CreateWindow(int x, int y, int w, int h, int* opt1, int* opt2, int*
 opt3, char* name);

 And if you want to create a certain type of window with some
 parameters which are always the same, you could create an alias that
 binds certain arguments to this function:

 alias bind!CreateWindow(void, void, width, height, null, null, null,
 void) myWindow;

 Here 'void' would designate arguments that you would have to fill in
 when calling myWindow.

 You would call it like:
 myWindow(posX, posY, "MyWindowName");

 which would translate the call to:
 CreateWindow(posX, posY, width, height, null, null, null, "MyWindowName");
I don't see the point reviving the std.bind module*. In your case a new function name 'myWindow' needs to be defined, which makes it easier to just create a wrapper function auto myWindow(int x, int y, char* name) { return CreateWindow(x, y, width, height, null, null, null, name); } *: http://www.digitalmars.com/d/2.0/phobos/std_bind.html
Apr 15 2011
parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 15.04.2011 22:24, KennyTM~ wrote:
 On Apr 16, 11 00:29, Andrej Mitrovic wrote:
 I've also tried to create a some sort of 'bind' function which could
 let you bind arguments to specific parameters of a function. If I had
 it working it would really help (me) out in coding for  e.g. the
 Windows API. For example you might have a WinAPI function such as (I'm
 pseudocoding here):

 CreateWindow(int x, int y, int w, int h, int* opt1, int* opt2, int*
 opt3, char* name);

 And if you want to create a certain type of window with some
 parameters which are always the same, you could create an alias that
 binds certain arguments to this function:

 alias bind!CreateWindow(void, void, width, height, null, null, null,
 void) myWindow;

 Here 'void' would designate arguments that you would have to fill in
 when calling myWindow.

 You would call it like:
 myWindow(posX, posY, "MyWindowName");

 which would translate the call to:
 CreateWindow(posX, posY, width, height, null, null, null, 
 "MyWindowName");
I don't see the point reviving the std.bind module*. In your case a new function name 'myWindow' needs to be defined, which makes it easier to just create a wrapper function auto myWindow(int x, int y, char* name) { return CreateWindow(x, y, width, height, null, null, null, name); } *: http://www.digitalmars.com/d/2.0/phobos/std_bind.html
I absolutely agree, also creating delegate in place solves pretty much all of std.bind use cases. -- Dmitry Olshansky
Apr 15 2011
prev sibling parent reply Lutger Blijdestijn <lutger.blijdestijn gmail.com> writes:
Nick Sabalausky wrote:

 "spir" <denis.spir gmail.com> wrote in message
 news:mailman.3497.1302788057.4748.digitalmars-d puremagic.com...
 On 04/13/2011 02:34 PM, bearophile wrote:

 If a value of type T can be null, it must be declared as type
 Optional<T>, which may be abbreviated to T?

 String? name = process.args.first;
 if (exists name) {
      writeLine("Hello " name "!");
 }
 else {
      writeLine("Hello World!");
 }

 Use of an optional value must be guarded by the if (exists ... )
 construct. Therefore, NullPointerExceptions are impossible.

 This is exactly what I suggested for D in a enhancement request.
 It seems this kind of stuff is becoming a standard in new languages.
+++ But I guess optionality could, and should, extend to non-ref types; thus, null is just a particular case of non-existence. And this would apply especially on function parameters: void f (int i?) {...}
Oh absolutely. Haxe has nullable-primatives which really comes in handly at times (it often prevents the need for a separate bool to keep track of). Only problem is that in Haxe, not only is nullable the default, but it doesn't even *have* any non-nullables at all, for any type.
 I don't get the diff between currying & partial app. And find this
 feature much complication for close to uselessness.
I'm not certain either, but I *think* partial application is just like currying except there's some sort of arbitrary limitaion on what combination(s) of paramaters you can choose to specify or not specify. And that limitation is based purely on what order the function defines its parameters. So basically, my understanding is that partial application is an arbitrarily-gimped currying.
partial application is getting a new function out of an existing one where one of the arguments is fixed / bound. More or less what std.functional curry does, confusingly. currying however doesn't involve specifying parameters at all, it means to get a function with one parameter out of a function with more than one parameter. This new function returns a function with one parameter, and so on and so forth until there is nothing left to curry. An example is clearer: int foo(int a, int b, int c) { return a + b + c; } auto curriedFoo(int a) { return (int b) { return (int c) { return foo(a, b, c); }; }; } assert( curriedFoo(1)(2)(3) == 6 ); Whereas partial application could be something like: auto partialApply(F)(int x, F fun) { return (ParameterTypeTuple!(F)[1..$] args) { return fun(x, args); }; } assert( partialApply(1, &foo)(2,3) == 6);
May 04 2011
parent reply bearophile <bearophileHUGS lycos.com> writes:
Lutger Blijdestijn:

 partial application is getting a new function out of an existing one where 
 one of the arguments is fixed / bound. More or less what std.functional 
 curry does, confusingly.
 [...]
A simple and good explanation. Regarding the name of std.functional.curry(), since some time I have suggested to rename it "partial". Bye, bearophile
May 04 2011
parent reply Cristi Cobzarenco <cristi.cobzarenco gmail.com> writes:
Currying is well established name as well, especially for people coming from
a functional programming background.

(Cristi Cobzarenco)
Profile: http://www.google.com/profiles/cristi.cobzarenco


On 4 May 2011 23:40, bearophile <bearophileHUGS lycos.com> wrote:

 Lutger Blijdestijn:

 partial application is getting a new function out of an existing one
where
 one of the arguments is fixed / bound. More or less what std.functional
 curry does, confusingly.
 [...]
A simple and good explanation. Regarding the name of std.functional.curry(), since some time I have suggested to rename it "partial". Bye, bearophile
May 05 2011
parent Max Klyga <max.klyga gmail.com> writes:
On 2011-05-06 00:54:34 +0300, Cristi Cobzarenco said:

 Currying is well established name as well, especially for people coming 
 from a functional programming background.
Current implementation does not curry the function, it partialy applies it. Currying is converting a function that takes multiple arguments to a function that takes first argument and returns a function that takes the second argument and do on. Curry ((a, b) -> c) -> a -> b -> c Uncurry (a -> b -> c) -> (a, b) -> c
 (Cristi Cobzarenco)
 Profile: http://www.google.com/profiles/cristi.cobzarenco
 
 
 On 4 May 2011 23:40, bearophile <bearophileHUGS lycos.com> wrote:
 Lutger Blijdestijn:
 
 partial application is getting a new function out of an existing one where
 one of the arguments is fixed / bound. More or less what std.functional
 curry does, confusingly.
 [...]
A simple and good explanation. Regarding the name of std.functional.curry(), since some time I have suggested to rename it "partial". Bye, bearophile
May 05 2011
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
spir:

 But I guess optionality could, and should, extend to non-ref types; thus, null
 is just a particular case of non-existence. And this would apply especially on
 function parameters:
    void f (int i?) {...}
not hard to implement them with the language itself).
 Also, they should reuse '?' to mean 'exists', possibly '!?' meaning the
opposite:
     void f (int i?) {
     if (? i) doWithI(i);
     if (!? i) doWithoutI();
     ...
 }
Better to keep the language less perlish.
 great! get rid of new in D as well
This was discussed a lot. I don't have much interest in this change.
 We may define a class method "by reference":

 void hello(String name) = hello;
???
The second hello is a function reference. Nothing so interesting to see here.
 I don't get the diff between currying & partial app.
Take a look at the wikipedia pages, the difference is small, they are quite related things, their difference is no so important: http://en.wikipedia.org/wiki/Currying http://en.wikipedia.org/wiki/Partial_application
 And find this feature much complication for close to uselessness.
In functional-style programming it's useful to be able to curry (or partially applicate) functions, it helps keep the code shorter and less noisy.
 examples?
See the first PDF at those pages. In the meantime people have mirrored those PDFs, see the Reddit thread.
 Yo; and while you're at "typestating", extend the feature to any type (not only
 pointers).
For this you may need to look for a language (Rust) designed for the ground up for this feature. Bye, bearophile
Apr 14 2011
next sibling parent reply spir <denis.spir gmail.com> writes:
On 04/14/2011 09:06 PM, bearophile wrote:
 But I guess optionality could, and should, extend to non-ref types; thus, null
  is just a particular case of non-existence. And this would apply especially on
  function parameters:
      void f (int i?) {...}
it's not hard to implement them with the language itself).
But I find optionality far more useful for non-ref types, since in the general case there is no truelly special or invalid value like null. What value means undefined/inexistent/non-provided, for an int? a bool? Unlike for ref'ed types (actual pointers/classes/arrays) we simply cannot express this without language support. This also leads to actual distinction of null and [] or "" for arrays & strings. Just dreaming... Denis -- _________________ vita es estrany spir.wikidot.com
Apr 14 2011
parent reply Jesse Phillips <jessekphillips+D gmail.com> writes:
spir Wrote:

 This also leads to actual distinction of null and [] or "" for arrays & 
 strings. Just dreaming...
Really? You want this? I really like that a null array is equal to an empty array. If you really care to find out if a string is null if(str is null)
Apr 14 2011
parent reply "Nick Sabalausky" <a a.a> writes:
"Jesse Phillips" <jessekphillips+D gmail.com> wrote in message 
news:io7oov$21d8$1 digitalmars.com...
 spir Wrote:

 This also leads to actual distinction of null and [] or "" for arrays &
 strings. Just dreaming...
Really? You want this? I really like that a null array is equal to an empty array.
I've thought about that and I don't know how I feel about it. On one hand, I can certainly image cases where the distiction between null and empty would be useful. But OTOH, after having to put up with the nightmare of VB6's "One million distinct ways to have a string that doesn't contain anything", I'm hesitent at embracing extra ways to have "ain't nuthin' here".
Apr 14 2011
parent Kagamin <spam here.lot> writes:
Nick Sabalausky Wrote:

 I've thought about that and I don't know how I feel about it. On one hand, I 
 can certainly image cases where the distiction between null and empty would 
 be useful. But OTOH, after having to put up with the nightmare of VB6's "One 
 million distinct ways to have a string that doesn't contain anything", I'm 
 hesitent at embracing extra ways to have "ain't nuthin' here".
 
In our project we use if(string.IsNullOrEmpty(str)){...} almost everywhere only in two places null matters. T__T
Apr 14 2011
prev sibling parent "Nick Sabalausky" <a a.a> writes:
"bearophile" <bearophileHUGS lycos.com> wrote in message 
news:io7gk3$1jea$1 digitalmars.com...
 spir:

 But I guess optionality could, and should, extend to non-ref types; thus, 
 null
 is just a particular case of non-existence. And this would apply 
 especially on
 function parameters:
    void f (int i?) {...}
it's not hard to implement them with the language itself).
(Ex: Missing IArithmetic, anyone?)
Apr 14 2011
prev sibling parent Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
On 13/04/2011 13:34, bearophile wrote:
 The first description of the Ceylon language, designed for business computing
(for large teams developing multi-user applications) and meant to replace Java,
from Red Hat, that will run on the Java Virtual Machine itself:
 http://blog.talawah.net/2011/04/gavin-king-unviels-red-hats-top-secret.html

 About the language (very slow download):
 http://www.qconbeijing.com/download/Gavin%20keynote.pdf
 About the its type system:
 http://www.qconbeijing.com/download/Gavin%20session.pdf
Hum, I saw this Ceylon stuff posted on Slashdot, and I've finally gotten around to taking a look at it. I don't have yet an opinion of the language as a whole, but I do like some of things they did or are thinking about. Namely, that they are extending or changing the type system, and not just to put in non-nullable types (which is quite simple to do), but going much further than that: looking at generics, covariance in generics (and in the process placing the immutability of collections in the type system instead of the runtime), being able to specify all possible subclasses of a class, union types, etc. Interesting ideas. -- Bruno Medeiros - Software Engineer
May 03 2011