Re: Example of Rust code

2012-08-12 Thread Marco Leise
Am Sun, 12 Aug 2012 00:17:44 +0200
schrieb Timon Gehr timon.g...@gmx.ch:

 On 08/11/2012 01:24 PM, Marco Leise wrote:
  Am Fri, 10 Aug 2012 15:56:53 +0200
  schrieb Timon Gehrtimon.g...@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?
 
 It means I won't keep a reference to *e, but I assume that is what
 was meant.
 
  What are the implications?
 
 The caller has some confidence that passing a pointer to stack-
 allocated data is safe.
 
  Does scope change the method signature?
 
 Yes. It is eg. impossible to override a method that has a scope
 parameter with a method that does not have a scope parameter.
 
  Does the compiler enforce something?
 
 In this case and currently, it is merely documentation.
 I think it should be enforced and cast(scope) should be added
 to allow non-@safe code to escape the conservative analysis.
 
  Will generated code differ?
 
 Only the mangled symbol name will differ. (unlike when scope is used on
 delegate parameters, in this case it prevents closure allocation at the
 call site.)
 
  Does it prevent bugs or is it documentation for the user of the function?
 
 It is just documentation, both for the user and the maintainer.
 
  Thanks in advance for some insight!
 

Now that looks like a good 'scope' FAQ. thx

-- 
Marco



Re: Example of Rust code

2012-08-12 Thread Paulo Pinto

Am 11.08.2012 20:37, schrieb Peter Alexander:

On Saturday, 11 August 2012 at 18:04:29 UTC, Paulo Pinto wrote:

On Saturday, 11 August 2012 at 16:12:14 UTC, Peter Alexander wrote:

On Saturday, 11 August 2012 at 14:45:55 UTC, Russel Winder wrote:

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


You missed the native efficiency part :-)


You mean like the Common Lisp compilers that are able to beat FORTRAN
compilers
in floating point computations?

http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.54.5725

--
Paulo


Not sure where you read that in the paper.

 From the conclusion:

We have demonstrated that the speed of compiled Common Lisp code,
though today somewhat slower than that of the best compiled Fortran,
could probably be as efficient, and in some ways superior.

Probably is the operative word there.


Should have re-read the paper. It has been a few years since I fully 
read it. Still I think Common Lisp code is pretty efficient.





Most modern Lisp implementations employ JITing one way or another, so
you do get native code. Just not on the first run through a bit of code.


JIT has its limits. A dynamically typed language is still dynamically
typed once compiled. Sure the JIT may be able to deduce the types in
some cases, but not all.

I do see your point, but in general it's still not as fast as optimised C.


I imagine you wanted to answer to Russel's post.

On Lisp's case, most systems available today only JIT when using the 
REPL, as you can always compile to native code.


Type annotations help improve the speed in hotspot areas of your code,
in case you really need the extra speed for the application use case.

As for the speed of native code produced by JITs for dynamic languages,
I think Cog(Smalltalk), Self(Smaltalk ended up becoming JVM Hotspot),
PyPy (Python), V8(JavaScript), LLVM(Julia) prove that you can get pretty 
close to C for the majority of use cases that matter to the common user.


Actually a running assumption among the dynamic languages advocates is that
if dynamic languages had had as much money and research support as the
static languages field, the compilers would be much better by now.

--
Paulo



Re: Example of Rust code

2012-08-12 Thread Johannes Pfau
Am Sun, 12 Aug 2012 00:17:44 +0200
schrieb Timon Gehr timon.g...@gmx.ch:

 On 08/11/2012 01:24 PM, Marco Leise wrote:
  Am Fri, 10 Aug 2012 15:56:53 +0200
  schrieb Timon Gehrtimon.g...@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?
 
 It means I won't keep a reference to *e, but I assume that is what
 was meant.
 
  What are the implications?
 
 The caller has some confidence that passing a pointer to stack-
 allocated data is safe.
 
  Does scope change the method signature?
 
 Yes. It is eg. impossible to override a method that has a scope
 parameter with a method that does not have a scope parameter.
 
  Does the compiler enforce something?
 
 In this case and currently, it is merely documentation.
 I think it should be enforced and cast(scope) should be added
 to allow non-@safe code to escape the conservative analysis.

There are probably some more, less known use cases. For example this
recent thread on stackoverflow shows how scope might be necessary to
initialize an immutable variable.
http://stackoverflow.com/questions/11860584/changing-immutable-members-inside-the-constructor




Re: Example of Rust code

2012-08-12 Thread bearophile

Paulo Pinto:

As for the speed of native code produced by JITs for dynamic 
languages,
I think Cog(Smalltalk), Self(Smaltalk ended up becoming JVM 
Hotspot),
PyPy (Python), V8(JavaScript), LLVM(Julia) prove that you can 
get pretty close to C for the majority of use cases that matter 
to the common user.


Among V8 developers thee are some ex Self developers.
I think at the moment there aren't enough Julia benchmarks to 
allow us to judge its performance well enough.
PyPy is surely not close to C speeds when it JITs Python code 
(PyPy developers need to stop using just their few benchmarks and 
try to optimize many other programs).

And you miss the best of the bunch, the Lua JIT.

One problem with JITs is that they give you a good performance if 
they are well implemented and if the the GC is good. While older 
languages produce decent performance even with a simple compiler.


Bye,
bearophile



Re: Example of Rust code

2012-08-12 Thread Paulo Pinto

On Sunday, 12 August 2012 at 11:28:28 UTC, bearophile wrote:

Paulo Pinto:

As for the speed of native code produced by JITs for dynamic 
languages,
I think Cog(Smalltalk), Self(Smaltalk ended up becoming JVM 
Hotspot),
PyPy (Python), V8(JavaScript), LLVM(Julia) prove that you can 
get pretty close to C for the majority of use cases that 
matter to the common user.


Among V8 developers thee are some ex Self developers.
I think at the moment there aren't enough Julia benchmarks to 
allow us to judge its performance well enough.
PyPy is surely not close to C speeds when it JITs Python code 
(PyPy developers need to stop using just their few benchmarks 
and try to optimize many other programs).

And you miss the best of the bunch, the Lua JIT.


Yeah, silly me forgeting about LuaJIT.



One problem with JITs is that they give you a good performance 
if they are well implemented and if the the GC is good. While 
older languages produce decent performance even with a simple 
compiler.


Bye,
bearophile



True, this year's Google IO V8 talk has lots of informations on 
how
you write JavaScript code can influence the code quality 
generated by V8.


From the compiler design geek I used to be, I find very 
interesting to
get myself informed about this area, and I think that dynamic 
languages JITs still have a lot of room to improve.


Although personally I prefer static languages with native 
compilers for my

own coding projects.

--
Paulo



Re: Example of Rust code

2012-08-12 Thread Timon Gehr

On 08/12/2012 10:17 AM, Johannes Pfau wrote:


There are probably some more, less known use cases. For example this
recent thread on stackoverflow shows how scope might be necessary to
initialize an immutable variable.
http://stackoverflow.com/questions/11860584/changing-immutable-members-inside-the-constructor




Such rules are not part of the current language. The comment that says
that they are is wrong. scope does not currently influence type
checking at method call boundaries.


Re: Example of Rust code

2012-08-11 Thread Jakob Ovrum

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.


Re: Example of Rust code

2012-08-11 Thread Russel Winder
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.win...@ekiga.net
41 Buckmaster Roadm: +44 7770 465 077   xmpp: rus...@winder.org.uk
London SW11 1EN, UK   w: www.russel.org.uk  skype: russel_winder


signature.asc
Description: This is a digitally signed message part


Re: Example of Rust code

2012-08-11 Thread Marco Leise
Am Fri, 10 Aug 2012 15:56:53 +0200
schrieb Timon Gehr timon.g...@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



Re: Example of Rust code

2012-08-11 Thread simendsjo

On Sat, 11 Aug 2012 13:24:12 +0200, Marco Leise marco.le...@gmx.de wrote:


Am Fri, 10 Aug 2012 15:56:53 +0200
schrieb Timon Gehr timon.g...@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.


Re: Example of Rust code

2012-08-11 Thread David Nadlinger

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


Re: Example of Rust code

2012-08-11 Thread Philippe Sigaud
On Sat, Aug 11, 2012 at 2:19 AM, David Piepgrass qwertie...@gmail.com wrote:

 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.

You mean AST for D code?

 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.)

I did it, maybe 2 years ago. I worked for recursive ADT too (lists,
trees) and automatically generated small matchers, and maybe specific
map/reduce.
That would be easier today, with this CTFE++ we now have.

IIRC, it generated an abstract class with internal subtypes and a tag
to distinguish the state. I guess I could have used a union for the
fields, like Timon did further upthread. Hmm, does a union allow for
recursive fields?

I never tried to do generic pattern matchers, that would work also on
any struct and class, by using .tupleof. I daydreamed about it a few
times, tough, but never found a palatable syntax. Maybe with the new
() = syntax, that'd be better.


 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.

Well, we are not far from having an official D lexer.
Then, an official D parser.

From this, adding user-defined extensions is not *that* complicated
(not simple, mind you, but doable).

* define lowerings (aka, translations from your extended syntax to D
syntax), maybe by snatching the unused macro keyword
* code a small wrapper around dmd, rdmd-like: given a file, it
extracts the macros, parses the extended code, transforms the
extensions, does that as many times as necessary, if some macros call
other macros.
* Discard the macros and then pass the transformed file to dmd.

It looks like C macros and preprocessor-based programming, but since
it knows the D grammar, it's nearer Lisp macros, I think.


Re: Example of Rust code

2012-08-11 Thread Artur Skawina
On 08/10/12 14:32, bearophile wrote:
 (Repost from D.learn.)
 
 Through Reddit I've found a page that shows a small example of Rust code:
 
 http://www.reddit.com/r/programming/comments/xyfqg/playing_with_rust/
 https://gist.github.com/3299083
 
 The code:
 https://gist.github.com/3307450
 
 -
 
 So I've tried to translate this first part of the Rust code to D (I have not 
 run it, but it looks correct):
 
 
 enum expr {
 val(int),
 plus(expr, expr),
 minus(expr, expr)
 }
 
 fn eval(e: expr) - int {
 alt *e {
   val(i) = i,
   plus(a, b) = eval(a) + eval(b),
   minus(a, b) = eval(a) - eval(b)
 }
 }
 
 fn main() {
 let x = eval(
 minus(val(5),
plus(val(3), val(1;
 
 io::println(#fmt(val: %i, x));
 }
 

Ugh. Haven't really read that article, but how about this
D version:

   import std.stdio;

   template ALIAS(alias A) { alias A ALIAS; }

   static struct Expr(string EVAL, A...) {
  A a;
  static if (is(typeof(a[0].eval)))
 @property a0() { return a[0].eval; }
  else
 alias ALIAS!(a[0]) a0;
  static if (is(typeof(a[1]))) {
 static if (is(typeof(a[1].eval)))
@property a1() { return a[1].eval; }
 else
alias ALIAS!(a[1]) a1;
  }
  @property auto eval() {
 static if (is(typeof(mixin(EVAL
return mixin(EVAL);
 else
mixin(EVAL);
  }
  //alias eval this; // Uncommenting this line will enable automatic
 // evaluation -- which may not always be desirable.

  auto opBinary(string op, B)(B b) {
 return Expr!(a0 ~ op ~ a1, Expr, B)(this, b);
  }
   }

   auto Val(V)(V v) { return Expr!(a0, V)(v); }

   void main() {
  auto r = Val(5) - (Val(3) + Val(1));
  writeln(r: , r,  == , r.eval);
  auto s = sqr(Val(5) * Val(2) ^^ Val(3));
  writeln(s: , s,  == , s.eval);
   }

   auto sqr(T)(T a) { return Expr!(a0*a0, T)(a); }

which is more readable while being much more powerful.

But still trivial enough that the compiler (GDC) evaluates it all
at compile time, even without being asked to do so.

artur


Re: Example of Rust code

2012-08-11 Thread Peter Alexander

On Saturday, 11 August 2012 at 14:45:55 UTC, Russel Winder wrote:

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


You missed the native efficiency part :-)

I think XL is the closest thing that currently exists.

http://en.wikipedia.org/wiki/XL_(programming_language)


Re: Example of Rust code

2012-08-11 Thread Paulo Pinto
On Saturday, 11 August 2012 at 16:12:14 UTC, Peter Alexander 
wrote:
On Saturday, 11 August 2012 at 14:45:55 UTC, Russel Winder 
wrote:

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


You missed the native efficiency part :-)

You mean like the Common Lisp compilers that are able to beat 
FORTRAN compilers

in floating point computations?

http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.54.5725

--
Paulo






Re: Example of Rust code

2012-08-11 Thread Russel Winder
On Sat, 2012-08-11 at 18:12 +0200, Peter Alexander wrote:
 On Saturday, 11 August 2012 at 14:45:55 UTC, Russel Winder wrote:
[…]
  quasi-troll
  Isn't that language Lisp?
  /quasi-troll
 
 You missed the native efficiency part :-)

Most modern Lisp implementations employ JITing one way or another, so
you do get native code. Just not on the first run through a bit of code.

[…]

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


signature.asc
Description: This is a digitally signed message part


Re: Example of Rust code

2012-08-11 Thread Peter Alexander

On Saturday, 11 August 2012 at 18:04:29 UTC, Paulo Pinto wrote:
On Saturday, 11 August 2012 at 16:12:14 UTC, Peter Alexander 
wrote:
On Saturday, 11 August 2012 at 14:45:55 UTC, Russel Winder 
wrote:

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


You missed the native efficiency part :-)

You mean like the Common Lisp compilers that are able to beat 
FORTRAN compilers

in floating point computations?

http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.54.5725

--
Paulo


Not sure where you read that in the paper.

From the conclusion:

We have demonstrated that the speed of compiled Common Lisp 
code, though today somewhat slower than that of the best compiled 
Fortran, could probably be as efficient, and in some ways 
superior.


Probably is the operative word there.

Most modern Lisp implementations employ JITing one way or 
another, so
you do get native code. Just not on the first run through a bit 
of code.


JIT has its limits. A dynamically typed language is still 
dynamically typed once compiled. Sure the JIT may be able to 
deduce the types in some cases, but not all.


I do see your point, but in general it's still not as fast as 
optimised C.


Re: Example of Rust code

2012-08-11 Thread Walter Bright

On 8/11/2012 11:04 AM, Paulo Pinto wrote:

On Saturday, 11 August 2012 at 16:12:14 UTC, Peter Alexander wrote:

You missed the native efficiency part :-)


You mean like the Common Lisp compilers that are able to beat FORTRAN compilers
in floating point computations?


Floating point code is a rather specialized subset of what a good native 
compiler can do.


For example, with Java, doing well with floating point has no relevance to the 
lack of user defined value types in Java, and the lack of efficiency that entails.


Re: Example of Rust code

2012-08-11 Thread Timon Gehr

On 08/11/2012 01:24 PM, Marco Leise wrote:

Am Fri, 10 Aug 2012 15:56:53 +0200
schrieb Timon Gehrtimon.g...@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?


It means I won't keep a reference to *e, but I assume that is what
was meant.


What are the implications?


The caller has some confidence that passing a pointer to stack-
allocated data is safe.


Does scope change the method signature?


Yes. It is eg. impossible to override a method that has a scope
parameter with a method that does not have a scope parameter.


Does the compiler enforce something?


In this case and currently, it is merely documentation.
I think it should be enforced and cast(scope) should be added
to allow non-@safe code to escape the conservative analysis.


Will generated code differ?


Only the mangled symbol name will differ. (unlike when scope is used on
delegate parameters, in this case it prevents closure allocation at the
call site.)


Does it prevent bugs or is it documentation for the user of the function?


It is just documentation, both for the user and the maintainer.


Thanks in advance for some insight!



Re: Example of Rust code

2012-08-11 Thread David Nadlinger

On Saturday, 11 August 2012 at 22:17:44 UTC, Timon Gehr wrote:

Will generated code differ?


Only the mangled symbol name will differ. (unlike when scope is 
used on
delegate parameters, in this case it prevents closure 
allocation at the call site.)


The code for callee stays the same, yes, but the code for the 
caller might change as the optimizer is free to take advantage of 
the fact that any reference in the parameters will not be escaped 
by the function. For example, LDC will stack-allocate dynamic 
arrays and objects if they are local to the function. [1]


David


[1] The fine print: We currently don't take advantage of scope 
parameters for this yet, though (it seems too dangerous with the 
related analysis not being implemented in the frontend), and for 
a completely unrelated reason, the code which performs the 
mentioned optimization is disabled in current master (but will be 
re-enabled in the near future, before the September release).


Re: Example of Rust code

2012-08-11 Thread Timon Gehr

On 08/12/2012 12:34 AM, David Nadlinger wrote:

On Saturday, 11 August 2012 at 22:17:44 UTC, Timon Gehr wrote:

Will generated code differ?


Only the mangled symbol name will differ. (unlike when scope is used on
delegate parameters, in this case it prevents closure allocation at
the call site.)


The code for callee stays the same, yes, but the code for the caller
might change as the optimizer is free to take advantage of the fact that
any reference in the parameters will not be escaped by the function. For
example, LDC will stack-allocate dynamic arrays and objects if they are
local to the function. [1]

David


[1] The fine print: We currently don't take advantage of scope
parameters for this yet, though (it seems too dangerous with the related
analysis not being implemented in the frontend),  and for a completely
unrelated reason, the code which performs the mentioned optimization is
disabled in current master (but will be re-enabled in the near future,
before the September release).


Is there an upper bound on the amount of allocated memory? Implicit
stack-allocation of arbitrarily-sized dynamic arrays seems dangerous.


Example of Rust code

2012-08-10 Thread bearophile

(Repost from D.learn.)

Through Reddit I've found a page that shows a small example of 
Rust code:


http://www.reddit.com/r/programming/comments/xyfqg/playing_with_rust/
https://gist.github.com/3299083

The code:
https://gist.github.com/3307450

-

So I've tried to translate this first part of the Rust code to D 
(I have not run it, but it looks correct):



enum expr {
val(int),
plus(expr, expr),
minus(expr, expr)
}

fn eval(e: expr) - int {
alt *e {
  val(i) = i,
  plus(a, b) = eval(a) + eval(b),
  minus(a, b) = eval(a) - eval(b)
}
}

fn main() {
let x = eval(
minus(val(5),
   plus(val(3), val(1;

io::println(#fmt(val: %i, x));
}


A comment from the little article:

putting a  in front of a expression allocates it on the stack 
and gives you a reference to it. so the lifetime of this tree is 
to the end of the run [main] function.


-

The first D version is easy enough to write, but:
- It uses classes, I think each class instance uses more memory 
than what's used in the original Rust code.
- All the class instances here are allocated on the Heap. This is 
less efficient than the Rust code, where all the data is 
stack-allocated.

- This code contains boilerplate, it's long.
- Writing eval() is easy, but in the first version of eval() 
there were two bugs.
- The assert(0) in eval() is not nice. There is no compile-time 
safety.

- The several dynamic casts in eval() are slow.


interface Expr {}

class Val : Expr {
const int v;
this(in int v_) pure nothrow {
this.v = v_;
}
}

class Plus : Expr {
const Expr x, y;
this(in Expr x_, in Expr y_) pure nothrow {
this.x = x_;
this.y = y_;
}
}

class Minus : Expr {
const Expr x, y;
this(in Expr x_, in Expr y_) pure nothrow {
this.x = x_;
this.y = y_;
}
}

int eval(in Expr e) pure nothrow {
if (Val ve = cast(Val)e)
return ve.v;
else if (Plus pe = cast(Plus)e)
return eval(pe.x) + eval(pe.y);
else if (Minus me = cast(Minus)e)
return eval(me.x) - eval(me.y);
else
assert(0);
}

void main() {
auto ex = new Minus(new Val(5),
new Plus(new Val(3),
 new Val(1)));

import std.stdio;
writeln(Val: , eval(ex));
}

-

This second D version uses the same class definitions, but 
allocates the class instances on the stack. The code is bug prone 
and ugly. The other disadvantages are unchanged:



void main() {
import std.stdio;
import std.conv: emplace;
import core.stdc.stdlib: alloca;

enum size_t size_Val = __traits(classInstanceSize, Val);
enum size_t size_Plus = __traits(classInstanceSize, Plus);
enum size_t size_Minus = __traits(classInstanceSize, Minus);

Val e1 = emplace!Val(alloca(size_Val)[0 .. size_Val], 5);
Val e2 = emplace!Val(alloca(size_Val)[0 .. size_Val], 3);
Val e3 = emplace!Val(alloca(size_Val)[0 .. size_Val], 1);
Plus e4 = emplace!Plus(alloca(size_Plus)[0 .. size_Plus], e2, 
e3);
Minus ex2 = emplace!Minus(alloca(size_Minus)[0 .. 
size_Minus], e1, e4);


writeln(Val: , eval(ex2));
}

-

A third D version, using tagged structs:
- It doesn't look nice, and it's long.
- Class references can be null, so I have added tests at runtime 
in the pre-conditions. In the Rust code the references can't be 
null.

- The structs are stack-allocated but the main() code is not nice.
- The tags can't const or immutable, otherwise the compiler 
doesn't read the actual value of the various tags, assuming it's 
always Tag.none.

- Too many casts make this code bug-prone.


import std.stdio;

enum Tag { none, val, plus, minus }

struct Expr {
Tag tag = Tag.none;
}

struct Val {
Tag tag = Tag.val;
immutable int v;

this(int v_) pure nothrow {
this.v = v_;
}
}

struct Plus {
Tag tag = Tag.plus;
const Expr* x, y;

this(in Expr* x_, in Expr* y_) pure nothrow
in {
assert(x_ != null);
assert(y_ != null);
} body {
this.x = x_;
this.y = y_;
}
}

struct Minus {
Tag tag = Tag.minus;
const Expr* x, y;

this(in Expr* x_, in Expr* y_) pure nothrow
in {
assert(x_ != null);
assert(y_ != null);
} body {
this.x = x_;
this.y = y_;
}
}

int eval(in Expr* e) pure nothrow
in {
assert(e);
} body {
final switch (e.tag) {
case Tag.none:
assert(0);
case Tag.val:
return (cast(Val*)e).v;
case Tag.plus:
auto pe = cast(Plus*)e;
return eval(pe.x) + eval(pe.y);
case Tag.minus:
auto me = cast(Minus*)e;
return eval(me.x) - eval(me.y);
}
}

void main() {
const e1 = Val(5);
const e2 = Val(3);
const e3 = Val(1);
const e4 = Plus(cast(Expr

Re: Example of Rust code

2012-08-10 Thread Tove

On Friday, 10 August 2012 at 12:32:28 UTC, bearophile wrote:


This second D version uses the same class definitions, but 
allocates the class instances on the stack. The code is bug 
prone and ugly. The other disadvantages are unchanged:



void main() {
import std.stdio;
import std.conv: emplace;
import core.stdc.stdlib: alloca;

enum size_t size_Val = __traits(classInstanceSize, Val);
enum size_t size_Plus = __traits(classInstanceSize, Plus);
enum size_t size_Minus = __traits(classInstanceSize, Minus);

Val e1 = emplace!Val(alloca(size_Val)[0 .. size_Val], 5);
Val e2 = emplace!Val(alloca(size_Val)[0 .. size_Val], 3);
Val e3 = emplace!Val(alloca(size_Val)[0 .. size_Val], 1);
Plus e4 = emplace!Plus(alloca(size_Plus)[0 .. size_Plus], 
e2, e3);
Minus ex2 = emplace!Minus(alloca(size_Minus)[0 .. 
size_Minus], e1, e4);


writeln(Val: , eval(ex2));
}

Probably there are ways to improve my D versions, or to write 
better versions.


Bye,
bearophile


I think version 2 would be the easiest one to improve, by 
including a combined emplace/alloca convenience function in 
Phobos for this common use-case.


See the technique used in:
http://www.digitalmars.com/d/archives/digitalmars/D/run-time_stack-based_allocation_166305.html

auto Create(void* buf=alloca(frame_size))





Re: Example of Rust code

2012-08-10 Thread Timon Gehr

One simple possibility is

import std.stdio;
struct Expr{
enum Tag { val, plus, minus }
union{int i;struct{Expr* a, b;}}
Tag tag;
}
Expr val(int i){ Expr e;e.tag=Expr.Tag.val;e.i=i;return e;}
Expr plus(Expr* a, Expr* b){Expr e;e.tag=Expr.Tag.plus; e.a=a; 
e.b=b;return e;}
Expr minus(Expr* a, Expr* b){Expr e;e.tag=Expr.Tag.minus; e.a=a; 
e.b=b;return e;}


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);
}
}
void main(){
auto five = val(5), three = val(3), one = val(1);
auto add  = plus(three, one);
auto sub  = minus(five, add);
auto x= eval(sub);
writeln(val: ,x);
}

It would of course be better if D supported ADTs.


Re: Example of Rust code

2012-08-10 Thread Walter Bright

On 8/10/2012 5:32 AM, bearophile wrote:

Through Reddit I've found a page that shows a small example of Rust code:


Here's the D version:
-
import std.stdio;

struct expr {
int val;
int eval() { return val; }
}

expr plus (expr a, expr b) { return expr(a.val + b.val); }
expr minus(expr a, expr b) { return expr(a.val - b.val); }

void main() {
auto x = minus(expr(5), plus(expr(3), expr(1))).eval();
writeln(val: , x);
}
--

And the generated code:

--
__Dmain comdat
assume  CS:__Dmain
L0: pushEAX
mov EAX,offset FLAT:_D3std5stdio6stdoutS3std5stdio4File
pushdword ptr FLAT:_DATA[0Ch]
pushdword ptr FLAT:_DATA[08h]
push1
push0Ah
callnear ptr 
_D3std5stdio4File18__T5writeTAyaTiTaZ5writeMFAyaiaZv

xor EAX,EAX
pop ECX
ret


I'd say we're doing all right.


Re: Example of Rust code

2012-08-10 Thread bearophile

Walter Bright:


I'd say we're doing all right.


Are you serious?

Bye,
bearophile


Re: Example of Rust code

2012-08-10 Thread bearophile

Tove:

I think version 2 would be the easiest one to improve, by 
including a combined emplace/alloca convenience function in 
Phobos for this common use-case.


See the technique used in:
http://www.digitalmars.com/d/archives/digitalmars/D/run-time_stack-based_allocation_166305.html

auto Create(void* buf=alloca(frame_size))


I see, thank you for the suggestion, seems interesting.
And thank you to Timon Gehr for his compacted code.

Walter's code seems to miss the point, but maybe he's trying to 
tell me something about very small demo programs.


Bye,
bearophile


Re: Example of Rust code

2012-08-10 Thread Walter Bright

On 8/10/2012 3:42 PM, bearophile wrote:

Walter Bright:


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.





Re: Example of Rust code

2012-08-10 Thread Walter Bright

On 8/10/2012 3:46 PM, bearophile wrote:

Walter's code seems to miss the point, but maybe he's trying to tell me
something about very small demo programs.


If you want something allocated on the stack, us a struct, not a class.
It's what structs are for.

You can also use templates with overloading to get stack allocated parametric 
polymorphism and zero runtime overhead.


What I mean is:

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.

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.


Re: Example of Rust code

2012-08-10 Thread Walter Bright

On 8/10/2012 4:19 PM, Walter Bright wrote:

You can also use templates with overloading to get stack allocated parametric
polymorphism and zero runtime overhead.


It appears that Rust does not have function overloading. Is this correct?


Re: Example of Rust code

2012-08-10 Thread Walter Bright

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.



Re: Example of Rust code

2012-08-10 Thread David Piepgrass

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.


Re: Example of Rust code

2012-08-10 Thread bearophile

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


Re: Example of Rust code

2012-08-10 Thread Walter Bright

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.





Re: Example of Rust code

2012-08-10 Thread Walter Bright

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 
:-)



Re: An example of Rust code

2012-08-10 Thread Alex Rønne Petersen

On 10-08-2012 03:44, bearophile wrote:

Sorry, my mistake again, this was meant for the main D newsgroup.

Bye,
bearophile


Please repost on the main newsgroup so it gets attention. :)

--
Alex Rønne Petersen
a...@lycus.org
http://lycus.org


Re: An example of Rust code

2012-08-10 Thread bearophile

Alex Rønne Petersen:


Please repost on the main newsgroup so it gets attention. :)


OK. But I don't know much much interested they will be :-)

Bye,
bearophile


An example of Rust code

2012-08-09 Thread bearophile
Through Reddit I've found a page that shows a small example of 
Rust code:


http://www.reddit.com/r/programming/comments/xyfqg/playing_with_rust/
https://gist.github.com/3299083

The code:
https://gist.github.com/3307450

-

So I've tried to translate this first part of the Rust code to D 
(I have not run it, but it looks correct):



enum expr {
val(int),
plus(expr, expr),
minus(expr, expr)
}

fn eval(e: expr) - int {
alt *e {
  val(i) = i,
  plus(a, b) = eval(a) + eval(b),
  minus(a, b) = eval(a) - eval(b)
}
}

fn main() {
let x = eval(
minus(val(5),
   plus(val(3), val(1;

io::println(#fmt(val: %i, x));
}


A comment from the little article:

putting a  in front of a expression allocates it on the stack 
and gives you a reference to it. so the lifetime of this tree is 
to the end of the run [main] function.


-

The first D version is easy enough to write, but:
- It uses classes, I think each class instance uses more memory 
than what's used in the original Rust code.
- All the class instances here are allocated on the Heap. This is 
less efficient than the Rust code, where all the data is 
stack-allocated.

- This code contains boilerplate, it's long.
- Writing eval() is easy, but in the first version of eval() 
there were two bugs.
- The assert(0) in eval() is not nice. There is no compile-time 
safety.

- The several dynamic casts in eval() are slow.


interface Expr {}

class Val : Expr {
const int v;
this(in int v_) pure nothrow {
this.v = v_;
}
}

class Plus : Expr {
const Expr x, y;
this(in Expr x_, in Expr y_) pure nothrow {
this.x = x_;
this.y = y_;
}
}

class Minus : Expr {
const Expr x, y;
this(in Expr x_, in Expr y_) pure nothrow {
this.x = x_;
this.y = y_;
}
}

int eval(in Expr e) pure nothrow {
if (Val ve = cast(Val)e)
return ve.v;
else if (Plus pe = cast(Plus)e)
return eval(pe.x) + eval(pe.y);
else if (Minus me = cast(Minus)e)
return eval(me.x) - eval(me.y);
else
assert(0);
}

void main() {
auto ex = new Minus(new Val(5),
new Plus(new Val(3),
 new Val(1)));

import std.stdio;
writeln(Val: , eval(ex));
}

-

This second D version uses the same class definitions, but 
allocates the class instances on the stack. The code is bug prone 
and ugly. The other disadvantages are unchanged:



void main() {
import std.stdio;
import std.conv: emplace;
import core.stdc.stdlib: alloca;

enum size_t size_Val = __traits(classInstanceSize, Val);
enum size_t size_Plus = __traits(classInstanceSize, Plus);
enum size_t size_Minus = __traits(classInstanceSize, Minus);

Val e1 = emplace!Val(alloca(size_Val)[0 .. size_Val], 5);
Val e2 = emplace!Val(alloca(size_Val)[0 .. size_Val], 3);
Val e3 = emplace!Val(alloca(size_Val)[0 .. size_Val], 1);
Plus e4 = emplace!Plus(alloca(size_Plus)[0 .. size_Plus], e2, 
e3);
Minus ex2 = emplace!Minus(alloca(size_Minus)[0 .. 
size_Minus], e1, e4);


writeln(Val: , eval(ex2));
}

-

A third D version, using tagged structs:
- It doesn't look nice, and it's long.
- Class references can be null, so I have added tests at runtime 
in the pre-conditions. In the Rust code the references can't be 
null.

- The structs are stack-allocated but the main() code is not nice.
- The tags can't const or immutable, otherwise the compiler 
doesn't read the actual value of the various tags, assuming it's 
always Tag.none.

- Too many casts make this code bug-prone.


import std.stdio;

enum Tag { none, val, plus, minus }

struct Expr {
Tag tag = Tag.none;
}

struct Val {
Tag tag = Tag.val;
immutable int v;

this(int v_) pure nothrow {
this.v = v_;
}
}

struct Plus {
Tag tag = Tag.plus;
const Expr* x, y;

this(in Expr* x_, in Expr* y_) pure nothrow
in {
assert(x_ != null);
assert(y_ != null);
} body {
this.x = x_;
this.y = y_;
}
}

struct Minus {
Tag tag = Tag.minus;
const Expr* x, y;

this(in Expr* x_, in Expr* y_) pure nothrow
in {
assert(x_ != null);
assert(y_ != null);
} body {
this.x = x_;
this.y = y_;
}
}

int eval(in Expr* e) pure nothrow
in {
assert(e);
} body {
final switch (e.tag) {
case Tag.none:
assert(0);
case Tag.val:
return (cast(Val*)e).v;
case Tag.plus:
auto pe = cast(Plus*)e;
return eval(pe.x) + eval(pe.y);
case Tag.minus:
auto me = cast(Minus*)e;
return eval(me.x) - eval(me.y);
}
}

void main() {
const e1 = Val(5);
const e2 = Val(3);
const e3 = Val(1);
const e4 = Plus(cast(Expr*)e2, cast(Expr*)e3

Re: An example of Rust code

2012-08-09 Thread bearophile

Sorry, my mistake again, this was meant for the main D newsgroup.

Bye,
bearophile