August 11, 2012
On 8/10/2012 5:02 PM, José Armando García Sancio wrote:
> On Fri, Aug 10, 2012 at 4:35 PM, Walter Bright
>> It appears that Rust does not have function overloading. Is this correct?
> That is correct.


Well, the type class thing looks like a lame substitute. Sorry.

August 11, 2012
>>> I'd say we're doing all right.
>>
>> Are you serious?
>
> Yes. What's wrong with my D version? It's short and to the point, works, and produces optimal code.

Your version is basically a very long-winded way to say "auto x = 5 - (3 + 1);" so it really has nothing to do with the example.

The point of the example was to represent a simple AST and store it on the stack, not to represent + and - operators as plus() and minus() functions.

(I must say though, that while ADTs are useful for simple ASTs, I am not convinced that they scale to big and complex ASTs, let alone extensible ASTs, which I care about more. Nevertheless ADTs are at least useful for rapid prototyping, and pattern matching is really nice too. I'm sure somebody could at least write a D mixin for ADTs, if not pattern matching.)

>1. If you write FORTRAN code in D, it will not work as well as writing
> FORTRAN in FORTRAN.
>2. If you write C code in D, it will not work as well as writing C in C.

Really? And here I genuinely thought D was good enough for all the things C and FORTRAN are used for.

>3. If you write Rust code in D, it will not work as well as writing Rust in Rust.

I hope someday to have a programming system whose features are not limited to whatever features the language designers saw fit to include -- a language where the users can add their own features, all the while maintaining "native efficiency" like D. That language would potentially allow Rust-like code, D-like code, Ruby-like code and even ugly C-like code.

I guess you don't want to be the one to kickstart that PL. I've been planning to do it myself, but so far the task seems just too big for one person.
August 11, 2012
Walter Bright:

Thank you for the answer.

> 3. If you write Rust code in D, it will not work as well as writing Rust in Rust.
>
> If you want D code to perform, you gotta write it in D. Not in Rust, C, or Java.

I agree. Every language has its strengths and its specific qualities, so you can't ask for a perfect translation from code in language X to language Y. On the other hand when X and Y languages are meant to be used for similar computing tasks, it's good to have some ways to translate the purposes of X code well enough to Y.

Regarding the problem David Piepgrass has explained what was the point of that Rust code, ans why your code was missing the point.

The main point of my little comparison was to show the usefulness of some Rust features that were discussed for D too, like pattern matching, tagged recursive structures (in Phobos there is std.variant.Algebraic, but it's currently not usable to write that code), and the original nice way of allocating a struct on the stack and return a reference to it, to build that expression tree.

I suggest to welcome future comparisons between D with Rust in this D newsgroup, because full ignorance of Rust will _not_ help D growth.

Bye,
bearophile
August 11, 2012
On 8/10/2012 3:42 PM, bearophile wrote:
> Walter Bright:
>
>> I'd say we're doing all right.
>
> Are you serious?

You can also do things called "expression templates" in D:


import std.stdio;

auto val(T)(T v) { static struct S { T v; int eval() { return v; }} auto s = S(v); return s; }

auto plus(A,B)(A a, B b) { static struct S { A a; B b; int eval() { return a.eval() + b.eval(); }} auto s = S(a,b); return s; }

auto minus(A,B)(A a, B b) { static struct S { A a; B b; int eval() { return a.eval() - b.eval(); }} auto s = S(a,b); return s; }

void main() {

    auto x = minus(val(5), plus(val(3), val(1)));

    writeln("val: ", x.eval());
}

relying on "parametric polymorphism". You could reduce the repetitive boilerplate by using a template mixin, but I just banged this out in a few minutes, and it illustrates the idea. Note that there is no heap allocation anywhere, nor even any testing/branching.

The compiler should inline this, but doesn't, but that's not a fault in D. The inliner could be improved.


August 11, 2012
On 8/10/2012 5:19 PM, David Piepgrass wrote:
> Your version is basically a very long-winded way to say "auto x = 5 - (3 + 1);"
> so it really has nothing to do with the example.
>
> The point of the example was to represent a simple AST and store it on the
> stack, not to represent + and - operators as plus() and minus() functions.

I see that now, and I presented a D way of doing it using "expression templates", a technique pioneered by C++ programmers.

Expression templates have been used before in D, in particular to implement a regular expression engine. Dmitry Olshansky has since shown how fantastic this is for generating incredibly fast regex engines.

As far as I know, only C++ and D have sufficiently powerful abstraction mechanisms to make this possible.


> Really? And here I genuinely thought D was good enough for all the things C and
> FORTRAN are used for.

If you're going to write C code, use a C compiler. It's possible to use D as a C compiler, but kinda pointless except as a transitory state towards using D capabilities.


> I hope someday to have a programming system whose features are not limited to
> whatever features the language designers saw fit to include -- a language where
> the users can add their own features, all the while maintaining "native
> efficiency" like D. That language would potentially allow Rust-like code, D-like
> code, Ruby-like code and even ugly C-like code.
>
> I guess you don't want to be the one to kickstart that PL. I've been planning to
> do it myself, but so far the task seems just too big for one person.

Andrei originally proposed to me a language like that. I talked him out of it :-)

August 11, 2012
Am Fri, 10 Aug 2012 15:56:53 +0200
schrieb Timon Gehr <timon.gehr@gmx.ch>:

> int eval(scope Expr* e){
>      final switch(e.tag) with(Expr.Tag){
>          case val:   return e.i;
>          case plus:  return eval(e.a) + eval(e.b);
>          case minus: return eval(e.a) - eval(e.b);
>      }
> }

Can you quickly explain the use of scope here? Does that mean "I wont keep a reference to e"?
What are the implications? Does scope change the method signature? Does the compiler enforce something? Will generated code differ? Does it prevent bugs or is it documentation for the user of the function?
Thanks in advance for some insight!

-- 
Marco

August 11, 2012
On Sat, 11 Aug 2012 13:24:12 +0200, Marco Leise <Marco.Leise@gmx.de> wrote:

> Am Fri, 10 Aug 2012 15:56:53 +0200
> schrieb Timon Gehr <timon.gehr@gmx.ch>:
>
>> int eval(scope Expr* e){
>>      final switch(e.tag) with(Expr.Tag){
>>          case val:   return e.i;
>>          case plus:  return eval(e.a) + eval(e.b);
>>          case minus: return eval(e.a) - eval(e.b);
>>      }
>> }
>
> Can you quickly explain the use of scope here? Does that mean "I wont keep a reference to e"?
> What are the implications? Does scope change the method signature? Does the compiler enforce something? Will generated code differ? Does it prevent bugs or is it documentation for the user of the function?
> Thanks in advance for some insight!
>

If I'm not mistaken, scope will enforce that the reference never escapes the function.
So you cannot pass it to other functions that might keep it's reference or store it in any way.
August 11, 2012
On Saturday, 11 August 2012 at 11:47:43 UTC, simendsjo wrote:
> If I'm not mistaken, scope will enforce that the reference never escapes the function.
> So you cannot pass it to other functions that might keep it's reference or store it in any way.

It _should_ enforce that, but its implementation is lacking at this point.

David
August 11, 2012
On Saturday, 11 August 2012 at 11:24:35 UTC, Marco Leise wrote:
> Can you quickly explain the use of scope here? Does that mean "I wont keep a reference to e"?
> What are the implications? Does scope change the method signature? Does the compiler enforce something? Will generated code differ? Does it prevent bugs or is it documentation for the user of the function?
> Thanks in advance for some insight!

The generated code is different when the parameter is a delegate (no closure is allocated in cases of anonymous functions/lamdas or expressions like &myNestedFunction). It's supposed to be enforced by the compiler that no references escape, but currently it's just documentation beyond the case of delegates.
August 11, 2012
On Sat, 2012-08-11 at 02:19 +0200, David Piepgrass wrote: […]
> I hope someday to have a programming system whose features are not limited to whatever features the language designers saw fit to include -- a language where the users can add their own features, all the while maintaining "native efficiency" like D. That language would potentially allow Rust-like code, D-like code, Ruby-like code and even ugly C-like code.
> 
> I guess you don't want to be the one to kickstart that PL. I've been planning to do it myself, but so far the task seems just too big for one person.

<quasi-troll>
Isn't that language Lisp?
</quasi-troll>

-- 
Russel. ============================================================================= Dr Russel Winder      t: +44 20 7585 2200   voip: sip:russel.winder@ekiga.net 41 Buckmaster Road    m: +44 7770 465 077   xmpp: russel@winder.org.uk London SW11 1EN, UK   w: www.russel.org.uk  skype: russel_winder