Discussion:
D to Javascript converter (a hacked up dmd)
Adam D. Ruppe
2012-02-27 03:51:21 UTC
Permalink
https://github.com/downloads/adamdruppe/dtojs/dtojs.zip

Daniel Murphy's microd fork of dmd, meant to output C,
made me realize it'd be fairly easy to use that same method
for other languages too.

So, I spent some time these last two weekends making it work
to put out Javascript.


See below for a copy/paste of the readme on how to get started.

A live demo:
http://arsdnet.net/dtojs/test.html

D source code:
http://arsdnet.net/dtojs/microd.d



As you can see, a lot of things work: functions, main,
most the operators, loops, if, basic data types,
even structs, classes (including inheritance), and exceptions.


Take a look at the generated javascript
http://arsdnet.net/dtojs/microd.js

It looks messy, since it uses mangled names almost everywhere.
(if you replace the mangled names with shorter things, it cuts
the size down by like 60%. Or, you can gzip it for a 10x
reduction.
See tools/mangledown.d in the zip, but this is raw so you can see
what it makes.)



For classes, it creates a vtable and some run time type
information
on the Javascript object. This allows dynamic casts and virtual
functions to work like you expect in D.

You can see _Dmain in the middle of the file, and at the bottom,
you can see it is called if present, so you can have one or not
have
one at your preference.

As you scroll down, you'll see the methods. Since I forked a C
generator, they are made and usually called as free functions,
but extern(js) (see below) are made as object properties.


Not so obvious is the runtime that's mixed in there.

Here's the D source code:
http://arsdnet.net/dtojs/object.d


It's pretty simple code. extern(js) works to let you - and other
JS things - easily interact with the outside world, since it
turns off mangling while letting you define things like loose
variadics.

There is no handwritten Javascript except for the if(_Dmain) at
the end. The rest of the runtime and library is written in D.



Speaking of library, I started something there too.

http://arsdnet.net/dtojs/browser/

the browser package generates no Javascript code. It simply
binds to existing functionality so D can use it in a more
structured manner. (object.d generates ~14kb of code when
raw. If you run mangledown on it, it goes down to about 6.)

browser.document provides some access to the browser DOM.

http://arsdnet.net/dtojs/std/

The std package is a kind of Phobos library, meant to make
source-compatible code with regular D stuff. It generates some
javascript.


I don't want to use the real Phobos though because it is fairly
large, and won't take advantage of the browser's existing library
functions. It *might* work in here though; I haven't tried.



The browser package makes no attempt at cross browser
compatibility,
but you can test for functions like you would in real JS:

if(&document.querySelector) { we have it }



If I start to use this thing seriously, I might provide a library
wrapper that does this kind of thing.






Anyway, it works pretty well in the trivial tests I've done
so far, but I haven't used it for anything more serious.



Kinda cool though, and hasn't been that hard. The dmd compiler
isn't so bad to hack up once you get to know it.

Combined with the stuff others and I have already done for
D on the server, we might just be coming up on web apps that
use the same D everywhere!

========
Here's how to use it:

First, copy in the backend folder from the dmd.zip you
get from Digital Mars.

(You need it to compile, but I don't have a license to
distribute it myself.)


Then, run make to build the hacked dmd.



When its done, change into the "test" directory and
start to play. The makefile there shows how to build
some javascript.

../dmd -md yourfile.d

and optionally you can use my library in there from
test/browser and test/std.(add std/*.d to the dmd
command line to make sure its code is generated in.)

You can ignore most the messages it spams out; it
will do its best to generate the file anyway.

test/browser is the kind of core runtime to this,
in addition to object.d.

object.d - the stuff D expects and the basic JS language
constructs

browser/*.d - bindings to objects and functions the browser
provides
such as the DOM.

Most global functions in the browser are found in
browser/window.d.


std/*.d - just super minimal wrappers to browser functions laid
out
more like Phobos.
Jacob Carlborg
2012-02-27 08:48:39 UTC
Permalink
Post by Adam D. Ruppe
https://github.com/downloads/adamdruppe/dtojs/dtojs.zip
Daniel Murphy's microd fork of dmd, meant to output C,
made me realize it'd be fairly easy to use that same method
for other languages too.
So, I spent some time these last two weekends making it work
to put out Javascript.
Interesting, and cool.
--
/Jacob Carlborg
Andrea Fontana
2012-02-27 09:46:50 UTC
Permalink
Cool!

Can you call custom (external, from 3rd party libs) JS functions from
there?
You should port jquery syntax sugar :)
Post by Jacob Carlborg
Post by Adam D. Ruppe
https://github.com/downloads/adamdruppe/dtojs/dtojs.zip
Daniel Murphy's microd fork of dmd, meant to output C,
made me realize it'd be fairly easy to use that same method
for other languages too.
So, I spent some time these last two weekends making it work
to put out Javascript.
Interesting, and cool.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d-announce/attachments/20120227/73ae2778/attachment.html>
Adam D. Ruppe
2012-02-27 15:09:41 UTC
Permalink
Post by Andrea Fontana
Can you call custom (external, from 3rd party libs)
JS functions from there?
Yes, just make:

extern(js) void function_name_here(...);

and you can call it. For jQuery, you'd probably want
to define an extern(js) class JQuery {} with all its method
names. Since so many of them take strings, I think this would
actually be somewhat easy.
Andrea Fontana
2012-02-27 15:39:50 UTC
Permalink
Post by Adam D. Ruppe
Post by Andrea Fontana
Can you call custom (external, from 3rd party libs)
JS functions from there?
extern(js) void function_name_here(...);
Good!
Post by Adam D. Ruppe
and you can call it. For jQuery, you'd probably want
to define an extern(js) class JQuery {} with all its method
names. Since so many of them take strings, I think this would
actually be somewhat easy.
About jquery: i mean what about a d function similar to $() jquery
function for better elements handling (instead of getElementById() )


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d-announce/attachments/20120227/edd00fb8/attachment.html>
Adam D. Ruppe
2012-02-27 15:55:53 UTC
Permalink
Post by Andrea Fontana
About jquery: i mean what about a d function similar to $()
jquery
function for better elements handling (instead of
getElementById() )
Have you seen my dom library? :P

It's all server side but it is just awesome. Lots of
convenience functions, getting elements is easy, and
operating on them as a group is too, either through
a wrapper struct or just using foreach yourself.

I definitely want to port some of it to the javascript
output.

https://github.com/adamdruppe/misc-stuff-including-D-programming-language-web-stuff
the file is dom.d. It also depends on characterencodings.d.

The most jquery-like interface is Document's opIndex:

document[`#something .my-thing > p`].addClass("matched")
.appendText("matched me!");


Though, I really think that querySelectorAll + foreach
wipes out jquery's element selection advantage.

querySelectorAll is in all browsers IE8 and up. Adding
foreach to javascript can be done with text macro
(see html.d in my github) or D->JS of course has foreach
too!


The zip of d->js actually breaks on foreach here, but
it was an easy fix. I'll push up the changes this next
weekend.


Anyway, here's how it looks:

foreach(element; document.querySelectorAll("#blah > p"))
// do something to element
Andrea Fontana
2012-02-27 16:44:54 UTC
Permalink
Post by Adam D. Ruppe
Post by Andrea Fontana
About jquery: i mean what about a d function similar to $()
jquery
function for better elements handling (instead of
getElementById() )
Have you seen my dom library? :P
Of course not!
Post by Adam D. Ruppe
It's all server side but it is just awesome. Lots of
convenience functions, getting elements is easy, and
operating on them as a group is too, either through
a wrapper struct or just using foreach yourself.
I definitely want to port some of it to the javascript
output.
https://github.com/adamdruppe/misc-stuff-including-D-programming-language-web-stuff
the file is dom.d. It also depends on characterencodings.d.
document[`#something .my-thing > p`].addClass("matched")
.appendText("matched me!");
Though, I really think that querySelectorAll + foreach
wipes out jquery's element selection advantage.
querySelectorAll is in all browsers IE8 and up. Adding
foreach to javascript can be done with text macro
(see html.d in my github) or D->JS of course has foreach
too!
The zip of d->js actually breaks on foreach here, but
it was an easy fix. I'll push up the changes this next
weekend.
foreach(element; document.querySelectorAll("#blah > p"))
// do something to element
Very interesting! :)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d-announce/attachments/20120227/c8cabefd/attachment-0001.html>
Daniel Murphy
2012-02-27 11:32:50 UTC
Permalink
"Adam D. Ruppe" <destructionator at gmail.com> wrote in message
Post by Adam D. Ruppe
https://github.com/downloads/adamdruppe/dtojs/dtojs.zip
Daniel Murphy's microd fork of dmd, meant to output C,
made me realize it'd be fairly easy to use that same method
for other languages too.
So, I spent some time these last two weekends making it work
to put out Javascript.
This is great - it might make javascript actually usable as a platform. =D

How come you didn't do this as a proper fork/branch of dmd? It seems like
doing it this way would make it harder to maintain, and it certainly makes
it harder to see what's been changed.

It's also not too hard to strip out the backend if you want to redistribute
the binary. (stub out e2ir,s2ir,glue,toobj,iasm and remove the backend
specific stuff from main)
Adam D. Ruppe
2012-02-27 15:16:15 UTC
Permalink
Post by Daniel Murphy
How come you didn't do this as a proper fork/branch of dmd?
At first, I downloaded a zip of your fork just to take a
look at it - I had no intention of actually modifying it.

But, then I started to play around and never cleaned
stuff up.

/home/me/d/toys/yebblies-dmd-7723455/src

That's the name of the directory where it lives on
my computer :)


I pushed it up to github last night right before
making the ng post as a last-minute decision, figuring
github would make it easier for people to look at.


Redoing it as a proper fork won't be that hard; most the
changes are in the one microd.c file anyway. Maybe I
will next weekend.
Post by Daniel Murphy
It's also not too hard to strip out the backend if you want to
redistribute
the binary. (stub out e2ir,s2ir,glue,toobj,iasm and remove the
backend specific stuff from main)
Cool. I took a quick look at doing that but just horribly
broke my build.

Isn't parts of ctfe implemented in glue.c though? I don't
see it obviously in there, but I thought I saw something
about that once.
Daniel Murphy
2012-02-28 03:06:09 UTC
Permalink
"Adam D. Ruppe" <destructionator at gmail.com> wrote in message
Post by Adam D. Ruppe
Post by Daniel Murphy
How come you didn't do this as a proper fork/branch of dmd?
At first, I downloaded a zip of your fork just to take a
look at it - I had no intention of actually modifying it.
But, then I started to play around and never cleaned
stuff up.
/home/me/d/toys/yebblies-dmd-7723455/src
That's the name of the directory where it lives on
my computer :)
I pushed it up to github last night right before
making the ng post as a last-minute decision, figuring
github would make it easier for people to look at.
Redoing it as a proper fork won't be that hard; most the
changes are in the one microd.c file anyway. Maybe I
will next weekend.
Cool, please do.
Post by Adam D. Ruppe
Post by Daniel Murphy
It's also not too hard to strip out the backend if you want to redistribute
the binary. (stub out e2ir,s2ir,glue,toobj,iasm and remove the backend
specific stuff from main)
Cool. I took a quick look at doing that but just horribly
broke my build.
Isn't parts of ctfe implemented in glue.c though? I don't
see it obviously in there, but I thought I saw something
about that once.
It really shouldn't be.
The big things I'm aware of that are in the wrong place in the compiler are
that overrides are verified when building the vtables in the glue layer,
finding 'this' inside functions is done in the glue, and a couple of things
are done too early (array ops, associative array re-writes).

You can pretty much just delete, e2ir, s2ir, and a couple of others, then
kill everything that calls them up until main. (warning - requires reading
linker speak) The main reason I left the glue layer intact in my branch is
because I was constantly referring to them for the more complex parts of
microD.

I had a branch somewhere where I did this, but I don't think it survived.
Don Clugston
2012-02-28 09:30:41 UTC
Permalink
Post by Adam D. Ruppe
Post by Daniel Murphy
How come you didn't do this as a proper fork/branch of dmd?
At first, I downloaded a zip of your fork just to take a
look at it - I had no intention of actually modifying it.
But, then I started to play around and never cleaned
stuff up.
/home/me/d/toys/yebblies-dmd-7723455/src
That's the name of the directory where it lives on
my computer :)
I pushed it up to github last night right before
making the ng post as a last-minute decision, figuring
github would make it easier for people to look at.
Redoing it as a proper fork won't be that hard; most the
changes are in the one microd.c file anyway. Maybe I
will next weekend.
Post by Daniel Murphy
It's also not too hard to strip out the backend if you want to redistribute
the binary. (stub out e2ir,s2ir,glue,toobj,iasm and remove the backend
specific stuff from main)
Cool. I took a quick look at doing that but just horribly
broke my build.
Isn't parts of ctfe implemented in glue.c though? I don't
see it obviously in there, but I thought I saw something
about that once.
CTFE is entirely implemented in interpret.c. Treatment of the runtime
part of (__ctfe) is in the glue layer, that's probably what you saw.
Adam D. Ruppe
2012-02-28 15:44:35 UTC
Permalink
Post by Don Clugston
CTFE is entirely implemented in interpret.c. Treatment of the
runtime part of (__ctfe) is in the glue layer, that's probably
what you saw.
Outstanding!


As a side note, I've been looking at dmdscript when I want
a detailed reference on Javascript, and it is (as to be expected)
written in a very similar style to dmd itself.

It's very nice. I like the dmd code now that I'm getting to know
it.
node
2012-02-27 12:10:16 UTC
Permalink
Does this mean I can do node.js in D? :)
Post by Adam D. Ruppe
https://github.com/downloads/adamdruppe/dtojs/dtojs.zip
Daniel Murphy's microd fork of dmd, meant to output C,
made me realize it'd be fairly easy to use that same method
for other languages too.
So, I spent some time these last two weekends making it work
to put out Javascript.
See below for a copy/paste of the readme on how to get started.
http://arsdnet.net/dtojs/test.html
http://arsdnet.net/dtojs/microd.d
As you can see, a lot of things work: functions, main,
most the operators, loops, if, basic data types,
even structs, classes (including inheritance), and exceptions.
Take a look at the generated javascript
http://arsdnet.net/dtojs/microd.js
It looks messy, since it uses mangled names almost everywhere.
(if you replace the mangled names with shorter things, it cuts
the size down by like 60%. Or, you can gzip it for a 10x
reduction.
See tools/mangledown.d in the zip, but this is raw so you can
see
what it makes.)
For classes, it creates a vtable and some run time type
information
on the Javascript object. This allows dynamic casts and virtual
functions to work like you expect in D.
You can see _Dmain in the middle of the file, and at the bottom,
you can see it is called if present, so you can have one or not
have
one at your preference.
As you scroll down, you'll see the methods. Since I forked a C
generator, they are made and usually called as free functions,
but extern(js) (see below) are made as object properties.
Not so obvious is the runtime that's mixed in there.
http://arsdnet.net/dtojs/object.d
It's pretty simple code. extern(js) works to let you - and other
JS things - easily interact with the outside world, since it
turns off mangling while letting you define things like loose
variadics.
There is no handwritten Javascript except for the if(_Dmain) at
the end. The rest of the runtime and library is written in D.
Speaking of library, I started something there too.
http://arsdnet.net/dtojs/browser/
the browser package generates no Javascript code. It simply
binds to existing functionality so D can use it in a more
structured manner. (object.d generates ~14kb of code when
raw. If you run mangledown on it, it goes down to about 6.)
browser.document provides some access to the browser DOM.
http://arsdnet.net/dtojs/std/
The std package is a kind of Phobos library, meant to make
source-compatible code with regular D stuff. It generates some
javascript.
I don't want to use the real Phobos though because it is fairly
large, and won't take advantage of the browser's existing
library
functions. It *might* work in here though; I haven't tried.
The browser package makes no attempt at cross browser
compatibility,
if(&document.querySelector) { we have it }
If I start to use this thing seriously, I might provide a
library
wrapper that does this kind of thing.
Anyway, it works pretty well in the trivial tests I've done
so far, but I haven't used it for anything more serious.
Kinda cool though, and hasn't been that hard. The dmd compiler
isn't so bad to hack up once you get to know it.
Combined with the stuff others and I have already done for
D on the server, we might just be coming up on web apps that
use the same D everywhere!
========
First, copy in the backend folder from the dmd.zip you
get from Digital Mars.
(You need it to compile, but I don't have a license to
distribute it myself.)
Then, run make to build the hacked dmd.
When its done, change into the "test" directory and
start to play. The makefile there shows how to build
some javascript.
../dmd -md yourfile.d
and optionally you can use my library in there from
test/browser and test/std.(add std/*.d to the dmd
command line to make sure its code is generated in.)
You can ignore most the messages it spams out; it
will do its best to generate the file anyway.
test/browser is the kind of core runtime to this,
in addition to object.d.
object.d - the stuff D expects and the basic JS language
constructs
browser/*.d - bindings to objects and functions the browser
provides
such as the DOM.
Most global functions in the browser are found in
browser/window.d.
std/*.d - just super minimal wrappers to browser functions laid
out
more like Phobos.
Adam D. Ruppe
2012-02-27 15:23:19 UTC
Permalink
Post by node
Does this mean I can do node.js in D? :)
Probably. When I did my testing, I ran the code in
dmdscript and later, firefox. The javascript it outputs
is pretty basic so I imagine it will work in any
engine.

To access the library, you can define them as
extern(js) functions or classes, and then some
global objects. In my code, check out src/test/browser
for examples - that package is just bindings to the
browser's functions.

Those are translated to javascript almost exactly
as you write it in D, giving access to the outside
world pretty naturally.



Remember though two important facts:

1) there's no optimization here. The D compiler just
spits out the code tree in the new language. So, don't
expect speed bonuses.

2) Not all of D works. But, a decent chunk of it does
and I think it's ready for some serious playing already.
Piotr Szturmaj
2012-02-28 19:28:04 UTC
Permalink
Post by Adam D. Ruppe
https://github.com/downloads/adamdruppe/dtojs/dtojs.zip
Daniel Murphy's microd fork of dmd, meant to output C,
made me realize it'd be fairly easy to use that same method
for other languages too.
So, I spent some time these last two weekends making it work
to put out Javascript.
Cool!

Can it compile a function to native code and JS simultaneously? I want
to execute the same code on both client and server side.
Adam D. Ruppe
2012-02-28 19:56:33 UTC
Permalink
On Tuesday, 28 February 2012 at 19:27:57 UTC, Piotr Szturmaj
Post by Piotr Szturmaj
Can it compile a function to native code and JS simultaneously?
I want to execute the same code on both client and server side.
You'd have to run dmd twice because it exits before getting
to the backend when doing js.

But you can run the same code:

dmd -md file.d # outputs file.js
dmd file.d # outputs file.exe


You might need versions or something for library support,
but that's just because I haven't ported much over yet.


I just now tried:

import std.algorithm;
auto range = sort!"a < b"(["b", "a"]);
window.alert(range.front);

.. and it produced 44 KB of Javascript
code that *almost* worked.

Looks like I have to fix the dollar expression,
but otherwise, almost usable.
Piotr Szturmaj
2012-02-29 02:42:43 UTC
Permalink
Post by Adam D. Ruppe
Post by Piotr Szturmaj
Can it compile a function to native code and JS simultaneously? I want
to execute the same code on both client and server side.
You'd have to run dmd twice because it exits before getting
to the backend when doing js.
dmd -md file.d # outputs file.js
dmd file.d # outputs file.exe
I see.
Post by Adam D. Ruppe
You might need versions or something for library support,
but that's just because I haven't ported much over yet.
I realize that work on project has just begun :)
Post by Adam D. Ruppe
import std.algorithm;
auto range = sort!"a < b"(["b", "a"]);
window.alert(range.front);
.. and it produced 44 KB of Javascript
code that *almost* worked.
44 KB - that's not bad!
Post by Adam D. Ruppe
Looks like I have to fix the dollar expression,
but otherwise, almost usable.
Some time ago, I was interested in translation to JS, but I rather
thought about binary translation, like in http://bellard.org/jslinux/.
There's similar "emscripten" project which translates LLVM bytecode to
JS: https://github.com/kripken/emscripten. And there's also commercial
Morfik: http://en.wikipedia.org/wiki/Morfik. Perhaps you might find
these links useful, if you don't know them already.
Adam D. Ruppe
2012-02-29 03:11:36 UTC
Permalink
On Wednesday, 29 February 2012 at 02:42:38 UTC, Piotr Szturmaj
Post by Piotr Szturmaj
44 KB - that's not bad!
It actually gets better: 9kb if you trim the mangled names
down to size (I've written a mangle name trimmer and an
unused function cutter; hello world is about 200 bytes.).


The reason it didn't work before wasn't just dollar, but also
ref params. This was a bit of a pain.. without pointers, how
can I implement this?

After thinking on it for almost an hour, I decided on passing
lambdas instead:

void a(ref b) { b = 10; }

int c = 5;
a(c);
assert(c == 10);


The JS looks like this:

function a(b) { b(10); }
var c = 5;
a(function(set) { if(typeof set != "undefined") c = set; return
c; });
c == 5 || _d_assert();


My implementation right now is a filthy hack... but std.algorithm
is basically working. assumeSorted's constructor is missing for
some reason, but the algorithm itself actually worked.

(I spent time making class constructors work, but I think I
neglected struct constructors, so probably easy fix.)



But, I think the best thing to do though isn't to port phobos
implementations, but instead port the interface as much as
possible.

sort can be a wrapper of Array.prototype.sort() from Javascript,
thus letting us leave out the implementation. Odds are the native
method will be faster anyway.
Post by Piotr Szturmaj
Some time ago, I was interested in translation to JS, but I
rather thought about binary translation, like in
http://bellard.org/jslinux/. There's similar "emscripten"
I've heard of these two, but they seem a lot bigger than
I like.

I want the generated JS to be as small as possible while
still covering a good chunk of D features.
Piotr Szturmaj
2012-02-29 03:24:23 UTC
Permalink
Post by Adam D. Ruppe
The reason it didn't work before wasn't just dollar, but also
ref params. This was a bit of a pain.. without pointers, how
can I implement this?
After thinking on it for almost an hour, I decided on passing
void a(ref b) { b = 10; }
int c = 5;
a(c);
assert(c == 10);
function a(b) { b(10); }
var c = 5;
a(function(set) { if(typeof set != "undefined") c = set; return c; });
c == 5 || _d_assert();
What about passing values within object?

function a(b) { b.value = 10; }
var c = 5;
var wrapper = { value: c };
a(wrapper);
c = wrapper.value;
Adam D. Ruppe
2012-02-29 03:30:00 UTC
Permalink
On Wednesday, 29 February 2012 at 03:24:17 UTC, Piotr Szturmaj
Post by Piotr Szturmaj
What about passing values within object?
Yeah, that's one of the first things I thought of, but
what about a more complex thing:

d = a(c) + 4;

where will the c=wrapper.value go?

It can't go at the end of the function call
now. Also, if the function call is in the
middle of something, we'd have to assign the
wrapper somewhere too. Suppose:

d = (c = 2, a(c));


I think anything that isn't inline for the
argument will be too easy to break.
Piotr Szturmaj
2012-02-29 04:02:59 UTC
Permalink
Post by Adam D. Ruppe
Post by Piotr Szturmaj
What about passing values within object?
Yeah, that's one of the first things I thought of, but
d = a(c) + 4;
where will the c=wrapper.value go?
It can't go at the end of the function call
now. Also, if the function call is in the
middle of something, we'd have to assign the
d = (c = 2, a(c));
I think anything that isn't inline for the
argument will be too easy to break.
Here's another try with objects:

function Wrapper(value) {
this.value = value;
}
Wrapper.prototype.valueOf = function() { return this.value; }
Wrapper.prototype.toString = function() { return this.value.toString(); }

function a(b) { b.value = 10 + b; }
var c = new Wrapper(5);
a(c);
alert(c); // shows 15

but this implies that all value variables must be initialized with new
Wrapper(x).
Adam D. Ruppe
2012-02-29 04:11:42 UTC
Permalink
On Wednesday, 29 February 2012 at 04:02:54 UTC, Piotr Szturmaj
Post by Piotr Szturmaj
but this implies that all value variables must be initialized
with new Wrapper(x).
Yeah. I don't like that because it means you pay for something
that you aren't necessarily going to use.

Now, it could follow the variable and say, if it is going into
a ref function, wrap it up like this, but that'd be a lot harder
to work into the compiler.


It's not a bad idea, though. If it can be arranged to only
be used when needed, it would probably be better than the
lambda.
Robert Clipsham
2012-02-29 09:18:23 UTC
Permalink
Post by Adam D. Ruppe
Post by Piotr Szturmaj
44 KB - that's not bad!
It actually gets better: 9kb if you trim the mangled names
down to size (I've written a mangle name trimmer and an
unused function cutter; hello world is about 200 bytes.).
You could probably still beat that if you ran it through Google's
closure compiler (on advanced!):

http://closure-compiler.appspot.com/home
--
Robert
http://octarineparrot.com/
Robert Clipsham
2012-02-29 09:27:52 UTC
Permalink
Post by Robert Clipsham
Post by Adam D. Ruppe
Post by Piotr Szturmaj
44 KB - that's not bad!
It actually gets better: 9kb if you trim the mangled names
down to size (I've written a mangle name trimmer and an
unused function cutter; hello world is about 200 bytes.).
You could probably still beat that if you ran it through Google's
http://closure-compiler.appspot.com/home
I actually just tried this with:

http://arsdnet.net/dtojs/microd.js

Original Size: 20.14KB (2.61KB gzipped)
Compiled Size: 3.05KB (1015 bytes gzipped)

Pretty impressive! It did spit out 86 warnings though...

Mostly:
* JSC_WRONG_ARGUMENT_COUNT
* JSC_USED_GLOBAL_THIS
* JSC_REDECLARED_VARIABLE
* JSC_NOT_A_CONSTRUCTOR (iirc to get around that you have to drop in a
/** @constructor */ comment before anything you want to use as a
constructor for that)

Good work at getting std.algorithm (mostly) working! :D
--
Robert
http://octarineparrot.com/
Adam D. Ruppe
2012-02-29 15:19:42 UTC
Permalink
On Wednesday, 29 February 2012 at 09:27:53 UTC, Robert Clipsham
Post by Robert Clipsham
Pretty impressive! It did spit out 86 warnings though...
A lot of it is probably the same kind of thing my
"linker" does. (I call it that, but it doesn't actually
*link* anything.)

I get down to 6 KB running it through that. Though, they
still cut it in half and there's some code rewriting in there
too. Not bad.


Fun fact btw: dmd -inline works on this thing too. Though,
inline makes a bunch of stuff in the form of (var a = 10, etc)
which is illegal in JS (and D, actually).


To hack that so it worked, I simply left the var out, so it
uses an implicit global variable. The D mangled names are unique
so I think it will work in practice, but still, blah.


Regardless, inlining functions is pretty cool. Might make
things bigger however, so idk if it is actually worth it.
Post by Robert Clipsham
* JSC_WRONG_ARGUMENT_COUNT
* JSC_REDECLARED_VARIABLE
I threw it a bone to silence some of these,
but much of it isn't actually wrong so meh.
Post by Robert Clipsham
* JSC_USED_GLOBAL_THIS
* JSC_NOT_A_CONSTRUCTOR
don't help at all. Even if I add the /**@constructor*/,
it just spits even more unhelpful warnings.

http://arsdnet.net/dtojs/test2.js

is where I put it. (the size there is tiny because I left
a lot of dead code in there; I just put a return; before my
other test code.)

JSC_TYPE_MISMATCH: actual parameter 1 of __d_6Object.call does
not match formal parameter
found : __d_6microd6MyBase
required: (__d_6Object|null|undefined) at line 2 character 17 in
test2.js__d_6Object.call(this, null); ^
JSC_INEXISTENT_PROPERTY: Property __d_vtbl never defined on
__d_6microd6MyBase at line 3 character 0 in
test2.jsthis.__d_vtbl.length = 3;


I call the Object initalizer (this isn't a constructor in D. The
real D compiler would just blit the Object.init to get the memory
started. The D constructor is passed as an argument to be called
at the end.) to set up that vtable.


So, I know its all right, but it is going to warn anyway.
Post by Robert Clipsham
Good work at getting std.algorithm (mostly) working! :D
Thanks!
Adam D. Ruppe
2012-02-29 15:46:38 UTC
Permalink
I found the std.algorithm problem. I skipped outputting
templated structs because it crashes my compiler.

For some reason.

microd.d(130): Error: variable t forward declaration
Segmentation fault.

Poo.

Function templates work fine, though.
Adam D. Ruppe
2012-02-29 17:21:28 UTC
Permalink
On Wednesday, 29 February 2012 at 15:46:40 UTC, Adam D. Ruppe
Post by Adam D. Ruppe
microd.d(130): Error: variable t forward declaration
Segmentation fault.
And that's fixed... and handling if(__ctfe)... and

boom! It worked. Generated 70 KB of javascript though,
a lot of it is obvious garbage - global variable declarations
and pieces of D code.

Looks like leftover stuff from CTFE and mixins. Probably
shouldn't be outputted at all, but it can be garbage collected
pretty well; my simple string search one brought it down to
40 KB.

Then, if I run my tools/mangledown, which replaces the D mangled
names with $number$, the size goes down to 6 KB.



6 KB isn't half bad! And got the right result from a complex
chunk of D code. (it just runs std.algorithm.sort on an array,
but that does a LOT of fancy stuff - string lambdas, treating
an array as a range, ctfe, and more.)

import std.algorithm;
void main() {
auto range = sort!"a < b"(["hello", "adam"]);
println(range.front); // "adam"
}



The Google thing can probably strip it more by shortening the
names more than my program does. (My name shortener doesn't
understand scoping - it is just a regex string replacer - so I'm
conservative in what it does.)



still hehehe, not bad at all.


BTW, I've written basic bindings to almost everything in the core
browser experience.

import jslang.name = the Javascript builtins, RegExp, Array, etc.
These generate no code, it is just like calling C from D.

import browser.name = Browser objects like JSON, document, window,
history, location, canvas, etc.

Again, generates no code, but gives access and static checks.




Now, I also wrote up a hack so you can do third party extensions,
with minimal generated code (especially if you use dmd -inline,
but even without it, it does well).


import browser.document;

final class MyElement {
extern(js) JSElement __js_this; // JSElement is the native
binding
// __js_ words have special meaning - they give direct access
to
// javascript keywords. use with care, it might not do what
you think.

// here, since object.this is nonsense in JS, the compiler
uses that
// to output object instead - giving direct access.
alias __js_this this; // alias this translates as A.member =
thing.
// but since member here is this, which is noop, it is just
plain A.

void addClass(string a) { className ~= " " ~ a; }
}


auto a = cast(MyElement) document.getElementById("something");

a.style.color = "green";
a.addClass("cool");


Generates (basically):

// it knows it is cast from final class to final class, which
// is a no-op in Javascript

var a = document.getElementById("something");
a.style.color = "green"; // directly output

addClass("cool", a); // the extension class is a free function

function addClass(a, d_this) {
d_this.className = d_this.className.concat(" ".concat(a));
}



alias this is cool. You can also do a real class, but don't
reinterpret cast to it - the vtbl will be missing. Instead,
just new it and let the compiler do its work.




This is getting pretty cool. Next challenge is the in operator.
In Javascript, in returns a boolean. D expects a pointer. How
can I do it efficiently?

The lambda trick will work for the pointer, but I don't want to
make that if we don't need it. Perhaps if the in expression
is immediately cast to bool, I'll skip it.



Another semanitc issue is:

ubyte a = 255;
a++; // we expect 0, but js will give 256.



I solved division:

int a = 1/2; // becomes var a = Math.floor(1/2);


And since D does a really good job at keeping int and float
math distinct, this is generally easy to work with.

float a = 1;
int b = a/2; // D requires an explicit cast here, so there's out
// Math.floor opportunity!

float b = a/2; // becomes just a/2.



But, wrapping might be fun. I could probably do & 0xff
if and only if D otherwise forces it to be a ubyte. But,
what about the bit pattern of negative numbers?

I could probably just ignore it, but I'd like to match as
much as is reasonable.
Piotr Szturmaj
2012-02-29 17:43:28 UTC
Permalink
Post by Adam D. Ruppe
But, wrapping might be fun. I could probably do & 0xff
if and only if D otherwise forces it to be a ubyte. But,
what about the bit pattern of negative numbers?
Take a look at WebGL's Typed Arrays. They allow explicit size integers
and binary operators. The disadvantage is they're supported only on
newest browsers.
Marco Leise
2012-03-02 21:50:40 UTC
Permalink
Post by Adam D. Ruppe
sort can be a wrapper of Array.prototype.sort() from Javascript,
thus letting us leave out the implementation. Odds are the native
method will be faster anyway.
That's right, although at least Google tries to implement the predefined functions in JS as well (that's what an engineer said in a video podcast)
sclytrack
2012-02-29 07:48:54 UTC
Permalink
Post by Adam D. Ruppe
Post by Piotr Szturmaj
Can it compile a function to native code and JS simultaneously? I want
to execute the same code on both client and server side.
You'd have to run dmd twice because it exits before getting
to the backend when doing js.
dmd -md file.d # outputs file.js
dmd file.d # outputs file.exe
You might need versions or something for library support,
but that's just because I haven't ported much over yet.
import std.algorithm;
auto range = sort!"a < b"(["b", "a"]);
window.alert(range.front);
.. and it produced 44 KB of Javascript
code that *almost* worked.
Looks like I have to fix the dollar expression,
but otherwise, almost usable.
Do you already have a name for the compiler?
Chad J
2012-02-29 01:47:29 UTC
Permalink
Fuck. Yes.

Combined with HTML5 <canvas> and such, this might be an awesome way to
write web-based games.

Please do more!
Bystroushaak
2012-02-29 16:56:06 UTC
Permalink
Post by Adam D. Ruppe
Daniel Murphy's microd fork of dmd, meant to output C
Link please.
Robert Clipsham
2012-02-29 17:03:57 UTC
Permalink
Post by Bystroushaak
Post by Adam D. Ruppe
Daniel Murphy's microd fork of dmd, meant to output C
Link please.
https://github.com/yebblies/dmd/tree/microd
--
Robert
http://octarineparrot.com/
Bystroushaak
2012-02-29 18:46:33 UTC
Permalink
Thx.
Post by Robert Clipsham
Post by Bystroushaak
Post by Adam D. Ruppe
Daniel Murphy's microd fork of dmd, meant to output C
Link please.
https://github.com/yebblies/dmd/tree/microd
Daniel Murphy
2012-03-01 08:05:16 UTC
Permalink
"Bystroushaak" <bystrousak at kitakitsune.org> wrote in message
Thx.
Post by Robert Clipsham
Post by Bystroushaak
Post by Adam D. Ruppe
Daniel Murphy's microd fork of dmd, meant to output C
Link please.
https://github.com/yebblies/dmd/tree/microd
Don't get your hopes up, it was more of an experiment than a serious fork, I
have no intention of doing anything more with it (unless I get really bored
again). It does work, but the effort is probably better spent on improving
gdc's support of embedded platforms.
Bystroushaak
2012-03-01 20:13:41 UTC
Permalink
I've played with gdc, but it's pretty complicated. I have few ADM 5120
routers with debwrt and it would be nice to be able compile D2 code
there, but so far, it was just fail.

C run pretty much everywhere and metacompiler D2C would be nice..
Post by Daniel Murphy
"Bystroushaak" <bystrousak at kitakitsune.org> wrote in message
Thx.
Post by Robert Clipsham
Post by Bystroushaak
Post by Adam D. Ruppe
Daniel Murphy's microd fork of dmd, meant to output C
Link please.
https://github.com/yebblies/dmd/tree/microd
Don't get your hopes up, it was more of an experiment than a serious fork, I
have no intention of doing anything more with it (unless I get really bored
again). It does work, but the effort is probably better spent on improving
gdc's support of embedded platforms.
Daniel Murphy
2012-03-02 01:19:07 UTC
Permalink
"Bystroushaak" <bystrousak at kitakitsune.org> wrote in message
Post by Bystroushaak
I've played with gdc, but it's pretty complicated. I have few ADM 5120
routers with debwrt and it would be nice to be able compile D2 code
there, but so far, it was just fail.
C run pretty much everywhere and metacompiler D2C would be nice..
I think once you get past the horror that is building gcc for your target
platform, the big issue remaining is that druntime needs to be ported.
You'll hit the same issue with a D->C translator, so it might be better just
to work on the actual runtime. Doing a proper gdc-based compiler should get
you some other nice things, like platform specific attributes/versions,
inline asm, and a better debugging experience.
Bystroushaak
2012-03-02 14:41:24 UTC
Permalink
Post by Daniel Murphy
I think once you get past the horror that is building gcc for your target
platform, the big issue remaining is that druntime needs to be ported.
There is actually gdc package in debwrt, but it is D1 :(
Post by Daniel Murphy
You'll hit the same issue with a D->C translator, so it might be better just
to work on the actual runtime.
Well, I don't consider myself as enough skilled programmer to work at gdc.
Johannes Pfau
2012-03-02 08:45:55 UTC
Permalink
Am Thu, 01 Mar 2012 21:13:41 +0100
Post by Bystroushaak
I've played with gdc, but it's pretty complicated. I have few ADM 5120
routers with debwrt and it would be nice to be able compile D2 code
there, but so far, it was just fail.
ADM 5120 is MIPS, right? Are you trying to build a cross compiler or a
compiler running on the MIPS itself? Making a cross-compiler is never
easy. Assuming you already have a C cross-compiler, you have to patch
the build process to include D at some point. You could also try
https://bitbucket.org/goshawk/gdc/wiki/crosstool-ng
but then you need a compatible 'sysroot' (a folder including the basic
libraries & headers as on your target system, must include libc &
some kernel headers, afaik) for your router.

Another issue: druntime/phobos might not compile (as long as
debwrt uses glibc it could work though), so configure with
--disable-phobos to disable both druntime and phobos. You'll only get
the compiler this way.

And MIPS is probably also affected by GDC issue 120, so you have to
configure like this:
DFLAGS="-fno-section-anchors" ./configure [configure arguments here]
Bystroushaak
2012-03-02 17:29:47 UTC
Permalink
Post by Johannes Pfau
ADM 5120 is MIPS, right? Are you trying to build a cross compiler or a
compiler running on the MIPS itself?
Compiler running on the MIPS.
Post by Johannes Pfau
And MIPS is probably also affected by GDC issue 120, so you have to
DFLAGS="-fno-section-anchors" ./configure [configure arguments here]
Thanks.
Andrei Alexandrescu
2012-02-29 17:32:44 UTC
Permalink
Post by Adam D. Ruppe
https://github.com/downloads/adamdruppe/dtojs/dtojs.zip
[snip]

That's interesting. So the idea is to make an entire subset of D
convertible to Javascript?

What use cases do you have in mind?


Andrei
Alex Rønne Petersen
2012-02-29 17:34:06 UTC
Permalink
Post by Andrei Alexandrescu
Post by Adam D. Ruppe
https://github.com/downloads/adamdruppe/dtojs/dtojs.zip
[snip]
That's interesting. So the idea is to make an entire subset of D
convertible to Javascript?
What use cases do you have in mind?
Andrei
Avoiding writing JS directly in web apps comes to mind.
--
- Alex
Nick Sabalausky
2012-02-29 17:46:13 UTC
Permalink
"Alex R?nne Petersen" <xtzgzorex at gmail.com> wrote in message
Post by Alex Rønne Petersen
Post by Andrei Alexandrescu
Post by Adam D. Ruppe
https://github.com/downloads/adamdruppe/dtojs/dtojs.zip
[snip]
That's interesting. So the idea is to make an entire subset of D
convertible to Javascript?
What use cases do you have in mind?
Andrei
Avoiding writing JS directly in web apps comes to mind.
Yea, creating JS without having to actually *write* JS is a huge use-case in
and of itself.

(I still can't believe the web has standardized on such an absolute shit
langauge. Hell, two of them if you count PHP on the server.)
Jacob Carlborg
2012-03-02 07:39:42 UTC
Permalink
"Alex R?nne Petersen"<xtzgzorex at gmail.com> wrote in message
Post by Alex Rønne Petersen
Post by Andrei Alexandrescu
Post by Adam D. Ruppe
https://github.com/downloads/adamdruppe/dtojs/dtojs.zip
[snip]
That's interesting. So the idea is to make an entire subset of D
convertible to Javascript?
What use cases do you have in mind?
Andrei
Avoiding writing JS directly in web apps comes to mind.
Yea, creating JS without having to actually *write* JS is a huge use-case in
and of itself.
(I still can't believe the web has standardized on such an absolute shit
langauge. Hell, two of them if you count PHP on the server.)
Five if you count HTML, CSS and SQL as well.
--
/Jacob Carlborg
Nick Sabalausky
2012-03-02 18:13:40 UTC
Permalink
"Jacob Carlborg" <doob at me.com> wrote in message
Post by Jacob Carlborg
"Alex R?nne Petersen"<xtzgzorex at gmail.com> wrote in message
Post by Alex Rønne Petersen
Post by Andrei Alexandrescu
Post by Adam D. Ruppe
https://github.com/downloads/adamdruppe/dtojs/dtojs.zip
[snip]
That's interesting. So the idea is to make an entire subset of D
convertible to Javascript?
What use cases do you have in mind?
Andrei
Avoiding writing JS directly in web apps comes to mind.
Yea, creating JS without having to actually *write* JS is a huge use-case in
and of itself.
(I still can't believe the web has standardized on such an absolute shit
langauge. Hell, two of them if you count PHP on the server.)
Five if you count HTML, CSS and SQL as well.
Very true, but a far as shittiness goes, JS and PHP are in a whole other
league (IMO).

Actually, HTML/CSS for what they are - *document* description formats -
really aren't all that bad. The only real *major* problem with HTML/CSS is
not the formats themselves, but the fact that people keep abusing them as
application presentation layers, which they clearly aren't and were never
intended to be. (And basing an entire application around the
deliberately-stateless HTTP? Seriously? WTF?)

Latex isn't bad (from what little I've seen), but if people started
pretending it was a presentation layer for programs, then yea, it would
completely blow for that. But that's exactly what people did with HTML/CSS.
So HTML and CSS get a bad reputation when really the true blame lies with
the people pushing for their misuse. (Not that HTML/CSS couldn't be improved
even as pure document formats.)
Jacob Carlborg
2012-03-03 12:24:10 UTC
Permalink
"Jacob Carlborg"<doob at me.com> wrote in message
Post by Jacob Carlborg
"Alex R?nne Petersen"<xtzgzorex at gmail.com> wrote in message
Post by Alex Rønne Petersen
Post by Andrei Alexandrescu
Post by Adam D. Ruppe
https://github.com/downloads/adamdruppe/dtojs/dtojs.zip
[snip]
That's interesting. So the idea is to make an entire subset of D
convertible to Javascript?
What use cases do you have in mind?
Andrei
Avoiding writing JS directly in web apps comes to mind.
Yea, creating JS without having to actually *write* JS is a huge use-case in
and of itself.
(I still can't believe the web has standardized on such an absolute shit
langauge. Hell, two of them if you count PHP on the server.)
Five if you count HTML, CSS and SQL as well.
Very true, but a far as shittiness goes, JS and PHP are in a whole other
league (IMO).
Yeah, I agree. I'm just saying, thank god I don't have to use PHP in my
job. I'm using CoffeeScript instead of JavaScript whenever I can which
makes it a bit more bearable. Yes I know many people here don't like CS,
specially the syntax, but it fixes several of the most annoying things
about JS.
Actually, HTML/CSS for what they are - *document* description formats -
really aren't all that bad. The only real *major* problem with HTML/CSS is
not the formats themselves, but the fact that people keep abusing them as
application presentation layers, which they clearly aren't and were never
intended to be. (And basing an entire application around the
deliberately-stateless HTTP? Seriously? WTF?)
Latex isn't bad (from what little I've seen), but if people started
pretending it was a presentation layer for programs, then yea, it would
completely blow for that. But that's exactly what people did with HTML/CSS.
So HTML and CSS get a bad reputation when really the true blame lies with
the people pushing for their misuse. (Not that HTML/CSS couldn't be improved
even as pure document formats.)
Yes, I think both HTML and CSS could be improved a lot. One of the most
annoying things is there's no good way to handle scoping. SASS
(regardless of which syntax you choose to use) makes this problem less
annoying and fixes several other issues with CSS. The fact that you most
likely uses a server side language to output HTML fixes many of the
problems with HTML.
--
/Jacob Carlborg
Ary Manzana
2012-03-01 18:04:35 UTC
Permalink
Post by Alex Rønne Petersen
Post by Andrei Alexandrescu
Post by Adam D. Ruppe
https://github.com/downloads/adamdruppe/dtojs/dtojs.zip
[snip]
That's interesting. So the idea is to make an entire subset of D
convertible to Javascript?
What use cases do you have in mind?
Andrei
Avoiding writing JS directly in web apps comes to mind.
I think it's cool you can convert D to JS, but I don't see why anyone
would want to do it.

1. JS is a superior language: variables are dynamic and are not bound to
just one single type during their lifetime. JS objects can store any
property.
2. JS funcions are much easier to write (no need to declare types) and
also to pass around (no need to write "&"). If you'd like to annotate
variables, you could use Closure:
https://developers.google.com/closure/compiler/docs/js-for-compiler
3. With JS you don't have to compile and run your code (well, I guess
you could make something smart in D for that).
4. If you write JS you can debug it in the browser. No need to track
back to the original source code.
5. If you don't like JS syntax or verbosity, you can use CoffeeScript,
which is just a syntax rewriter, not a language/paradigm shift:
http://coffeescript.org/
6. Javascript objects have some built-in properties that are different
from D. So implementing those in D would make their performance worse
(but you can always hard-code those functions into the compiler and
translate them directly to their JS equivalent).

The good thing about writing in D is that you could probably get some
IDE for autocompletion and such. You might also like to type things
instead of using dynamic types.
Timon Gehr
2012-03-01 18:48:00 UTC
Permalink
Post by Ary Manzana
I think it's cool you can convert D to JS, but I don't see why anyone
would want to do it.
[snip.]
Nope.
Alex Rønne Petersen
2012-03-01 18:56:06 UTC
Permalink
Post by Ary Manzana
Post by Alex Rønne Petersen
Post by Andrei Alexandrescu
Post by Adam D. Ruppe
https://github.com/downloads/adamdruppe/dtojs/dtojs.zip
[snip]
That's interesting. So the idea is to make an entire subset of D
convertible to Javascript?
What use cases do you have in mind?
Andrei
Avoiding writing JS directly in web apps comes to mind.
I think it's cool you can convert D to JS, but I don't see why anyone
would want to do it.
1. JS is a superior language: variables are dynamic and are not bound to
just one single type during their lifetime. JS objects can store any
property.
You're arguing with a crowd gathered around a statically typed language.
I think we can predict what this argument will lead to. :)
Post by Ary Manzana
2. JS funcions are much easier to write (no need to declare types) and
also to pass around (no need to write "&"). If you'd like to annotate
https://developers.google.com/closure/compiler/docs/js-for-compiler
See the above.
Post by Ary Manzana
3. With JS you don't have to compile and run your code (well, I guess
you could make something smart in D for that).
? The D -> JS converter just translates it. It's no different from
running e.g. the CoffeeScript compiler.
Post by Ary Manzana
4. If you write JS you can debug it in the browser. No need to track
back to the original source code.
Valid argument. Maybe we can make the D -> JS converter help in some way
here?
Post by Ary Manzana
5. If you don't like JS syntax or verbosity, you can use CoffeeScript,
http://coffeescript.org/
Don't even get me started on the horrible "features" in CoffeeScript.
The guy who wrote the language literally had no clue what he was doing
(he admitted to reading some "make your own language" book), and it
isn't much better than JavaScript in terms of odd behavior and weird
design decisions.
Post by Ary Manzana
6. Javascript objects have some built-in properties that are different
from D. So implementing those in D would make their performance worse
(but you can always hard-code those functions into the compiler and
translate them directly to their JS equivalent).
Can you be a little more specific here?
Post by Ary Manzana
The good thing about writing in D is that you could probably get some
IDE for autocompletion and such. You might also like to type things
instead of using dynamic types.
To be fair, excellent JS IDEs exist already; Visual Studio has great JS
auto-completion, and ReSharper enhances it a lot too.
--
- Alex
Adam D. Ruppe
2012-03-01 19:11:16 UTC
Permalink
On Thursday, 1 March 2012 at 18:56:07 UTC, Alex R?nne Petersen
Post by Alex Rønne Petersen
Valid argument. Maybe we can make the D -> JS converter help in
some way here?
I don't know yet. assert() in your D code, while a far cry
from a real debugger, does have the decency to give file
and line number in your browser error log, like so:

Error: uncaught exception: tests.d:9 [object.AssertError]
Assertion failure

in firefox, but it works in IE and I assume the others too.


Debugging in javascript is sure to be painful due to two
big facts though: 1) the line/file won't match up, and
2) the function and variable names are mangled, which gets
RIDICULOUSLY long in places, and very difficult to read.


For debugging, I might just put comments in the source
code.

/* file.d:30 */ var some_long_horrible_mangled_name = 20;

so at least you'd have a hope of reading it, by matching
it back up to your original source. This would be fairly
easy to implement and is better than nothing.



But, I don't know yet. For what I've done so far, a combination
of asserts and manually picking the generated code apart has
been what I use.
Jacob Carlborg
2012-03-01 20:09:05 UTC
Permalink
Post by Alex Rønne Petersen
Post by Ary Manzana
3. With JS you don't have to compile and run your code (well, I guess
you could make something smart in D for that).
? The D -> JS converter just translates it. It's no different from
running e.g. the CoffeeScript compiler.
It's quite a difference. The semantics of CoffeeScript and JavaScript is
more alike than D and JavaScript. CoffeeScript was created to be compile
to JavaScript, not something you could say about D.
Post by Alex Rønne Petersen
Post by Ary Manzana
4. If you write JS you can debug it in the browser. No need to track
back to the original source code.
Valid argument. Maybe we can make the D -> JS converter help in some way
here?
Similar problem with CoffeeScript, not as bad as with D since it outputs
readable JavaScript.
Post by Alex Rønne Petersen
Post by Ary Manzana
5. If you don't like JS syntax or verbosity, you can use CoffeeScript,
http://coffeescript.org/
Don't even get me started on the horrible "features" in CoffeeScript.
The guy who wrote the language literally had no clue what he was doing
(he admitted to reading some "make your own language" book), and it
isn't much better than JavaScript in terms of odd behavior and weird
design decisions.
It's way way WAY more better than JavaScript.

* Class based object model
* Function binding, language support for binding the this reference

If CoffeeScript had only these two features it would be so much more
useful than JavaScript, but it has a lot more:

* Extremely short function/lambda syntax
* Built-in loop comprehension
* == behaves as you would expect
* Existential operator
* Default arguments
* Variadic arguments
* Object syntax
* foreach loop that actually makes sense
* Almost everything is an expression
* No need to declare variables
* Implicit returns
* No need for semicolons (yeah, I know JS have this as well but most
don't seem to use this feature)
* Ranges
* Arrays slicing
Post by Alex Rønne Petersen
Post by Ary Manzana
6. Javascript objects have some built-in properties that are different
from D. So implementing those in D would make their performance worse
(but you can always hard-code those functions into the compiler and
translate them directly to their JS equivalent).
Can you be a little more specific here?
Post by Ary Manzana
The good thing about writing in D is that you could probably get some
IDE for autocompletion and such. You might also like to type things
instead of using dynamic types.
To be fair, excellent JS IDEs exist already; Visual Studio has great JS
auto-completion, and ReSharper enhances it a lot too.
--
/Jacob Carlborg
Adam D. Ruppe
2012-03-01 19:23:18 UTC
Permalink
Post by Ary Manzana
6. Javascript objects have some built-in properties that are
different from D. So implementing those in D would make their
performance worse (but you can always hard-code those functions
into the compiler and translate them directly to their JS
equivalent).
It's not so bad. In my zip, src/test/jslang provides bindings
to these things, which generate no code to use.

In src/test/std, I implement some Phobos interfaces this way.
(Run with dmd -inline and they generate no extra code.)

module std.string;

import jslang.string;

string replace(string a, string b, string c) {
auto s = cast(JSString) a; // cast just to appease D
return s.replace(b, c); // uses the built in method
}


...come to think of it, I think that's wrong. replace() in JS
only does the first occurrence iirc. D expects them all. But,
we could do:


import jslang.string;
import jslang.regexp;

string replace(string a, string b, string c) {
auto s = cast(JSString) a; // cast just to appease D
return s.replace(new RegExp(b, "g"), c); // uses the built in
method
}

or something like that.




But, none of this is hard coded in the compiler. You can
call javascript functions just like anything else, given
a prototype.

Object eval(...); // don't bother typing the arguments if you
don't want to
Jacob Carlborg
2012-03-01 19:57:47 UTC
Permalink
Post by Ary Manzana
Post by Alex Rønne Petersen
Post by Andrei Alexandrescu
Post by Adam D. Ruppe
https://github.com/downloads/adamdruppe/dtojs/dtojs.zip
[snip]
That's interesting. So the idea is to make an entire subset of D
convertible to Javascript?
What use cases do you have in mind?
Andrei
Avoiding writing JS directly in web apps comes to mind.
I think it's cool you can convert D to JS, but I don't see why anyone
would want to do it.
1. JS is a superior language: variables are dynamic and are not bound to
just one single type during their lifetime. JS objects can store any
property.
I really miss static typing sometimes in my day to day work (Ruby, JS, ...).
Post by Ary Manzana
2. JS funcions are much easier to write (no need to declare types) and
also to pass around (no need to write "&"). If you'd like to annotate
https://developers.google.com/closure/compiler/docs/js-for-compiler
D's new lambda syntax is way more superior than the one in JS. Most of
the times I would like to be able to specify types in function declarations.
Post by Ary Manzana
3. With JS you don't have to compile and run your code (well, I guess
you could make something smart in D for that).
True.
Post by Ary Manzana
4. If you write JS you can debug it in the browser. No need to track
back to the original source code.
True. But if you're compiler is good enough that won't be a problem,
i.e. CoffeeScript.
Post by Ary Manzana
5. If you don't like JS syntax or verbosity, you can use CoffeeScript,
http://coffeescript.org/
Already doing that. But if you're doing that you would most likley
pre-compile it and have the same problems as 3. and 4.
Post by Ary Manzana
6. Javascript objects have some built-in properties that are different
from D. So implementing those in D would make their performance worse
(but you can always hard-code those functions into the compiler and
translate them directly to their JS equivalent).
The good thing about writing in D is that you could probably get some
IDE for autocompletion and such. You might also like to type things
instead of using dynamic types.
--
/Jacob Carlborg
Nick Sabalausky
2012-03-02 05:52:10 UTC
Permalink
"Ary Manzana" <ary at esperanto.org.ar> wrote in message
Post by Ary Manzana
I think it's cool you can convert D to JS, but I don't see why anyone
would want to do it.
1. JS is a superior language: variables are dynamic and are not bound to
just one single type during their lifetime. JS objects can store any
property.
2. JS funcions are much easier to write (no need to declare types) and
also to pass around (no need to write "&").
Are you insane or just masochistic? ;)
Post by Ary Manzana
3. With JS you don't have to compile and run your code (well, I guess you
could make something smart in D for that).
Meh. I've done a lot of web work where "no compile" is common, and I've
never seen it as really being that big of a deal (unless you're using
something like C++ that takes ages to compile). It's an overrated selling
point of such langauges, IMO, much like "Our langauge doesn't require
semicolons!" Meh, so what? Trivialities.
Post by Ary Manzana
4. If you write JS you can debug it in the browser. No need to track back
to the original source code.
Not a bad point. Although Adam's suggestion does help mitigate it.
Post by Ary Manzana
5. If you don't like JS syntax or verbosity, you can use CoffeeScript,
http://coffeescript.org/
Bleh. I hate JS with a passion and I'd still much rather use straight JS
than CoffeeScript. CoffeeScript has a few nice bits of sugar, but the basic
syntax is just plain horrid. At least plain JS doesn't have that
indent-syntax abomination that's so popular these days.
Post by Ary Manzana
6. Javascript objects have some built-in properties that are different
from D. So implementing those in D would make their performance worse (but
you can always hard-code those functions into the compiler and translate
them directly to their JS equivalent).
If you're doing any non-trivial JS, you can *expect* it to be slow, period.
This is like saying "I drive a $100k sports car with 600 horsepower and yet
I care about my gas mileage". Just kinda goofy.
Adam D. Ruppe
2012-02-29 17:39:49 UTC
Permalink
On Wednesday, 29 February 2012 at 17:32:42 UTC, Andrei
Post by Andrei Alexandrescu
So the idea is to make an entire subset of
D convertible to Javascript?
What use cases do you have in mind?
Andrei
Adam D. Ruppe
2012-02-29 17:58:46 UTC
Permalink
Sorry if I sent twice, it is so easy to hit the
wrong button on things.

On Wednesday, 29 February 2012 at 17:32:42 UTC, Andrei
So the idea is to make an entire subset of D convertible to
Javascript?
Yeah, and I'm pretty much there - I just built a
little sort program with std.algorithm to it, which
is pretty cool.
What use cases do you have in mind?
A number of things:

1) The obvious one is writing the client side portions
of a web app in D, as well as the server side portions.

This gives all kinds of benefits: well, just think how
much better D is than all other languages for both little
and big things.

I really like having static checking of names and types.

D syntax is amazing. (Javascript really isn't bad here;
add a foreach macro and it isn't bad at all. But D is
still better.)

Sane libraries. You could use something like an include
macro in Javascript, or those insane client side add
script tag include functions, but here, you can just
use D's superior import system.

You get namespacing, stripping what you don't use;
all the advantages D brings to the table for any app.



Well, I'm sure I don't have to sell the D language
to you!



2) Using the same language for client and server means
you can reuse code. Library functions, field validation,
building parts of the site.

No duplication of effort for the two locations.

(Now this is already kinda small, since calling D functions
from Javascript isn't hard thanks to ajax - my web.d
makes it stupid easy by automatically wrapping functions.

But, that does require a trip to the server, so it isn't
always suitable.)



3) You don't need to write javascript at all! Imagine
you want to write an iPad app.

Apple wants you do fork over all kinds of dough and play
ball by their rules. I expect we'll see a D compiler that
can output code for that platform soon, but there's
another option that avoids all this right now: a web app
(which you can make full screen on the home page btw).

But, writing web apps means javascript. Gross.


No more! Just write the whole thing as D, then convert
it to Javascript and offer that to the ipad users.

I've started doing things like porting std.file to
use browser local storage, so you can pretend to use
files and have it save there too.




4) This is an insane idea, but one that came to mind.
I'm testing this by piping the generated JS into
dmdscript.

dmd runs insanely fast when compiling this code. Phobos
is kinda slow to compile, but you don't have to use it
here. Write D1 style code and dmd is blink of an eye.

dmdscript is reasonably fast too.



Suppose you're writing an app and you want a scripting
extension. Embed dmdscript, boom you can use javascript.

(I really want to revive a dmdscript D2 port to make this
even easier, but it isn't hard right now either.)


What if you want to script in D? If you're GPL... embed
dmd front end too.


Make D output JS, which is interpreted by D, calling
D apis....


Pretty insane, but you could script your app in D without
doing shared libraries or anything like that!




Compared to cases 1-3 though, this is silly. Just a thought
that came to mind.



The web app use case is strong though. I think I'll actually
use this thing.
Dmitry Olshansky
2012-02-29 19:10:22 UTC
Permalink
On 29.02.2012 21:58, Adam D. Ruppe wrote:
[...]
Post by Adam D. Ruppe
4) This is an insane idea, but one that came to mind.
I'm testing this by piping the generated JS into
dmdscript.
dmd runs insanely fast when compiling this code. Phobos
is kinda slow to compile, but you don't have to use it
here. Write D1 style code and dmd is blink of an eye.
dmdscript is reasonably fast too.
As someone that spent quite some time porting and fixing dmdscript I
humbly suggest using Google's standalone version of v8.

I mean I've done benchmarking, and it was like 20-200x times slower
depending on the things you do. For one hashtables are the bottleneck, I
though of reworking them but lost interest along the way. The other
problem is FP speed since JS uses double for eveerything. dmd used FP
stack for double back then, probably now it uses SSE(?).
Post by Adam D. Ruppe
Suppose you're writing an app and you want a scripting
extension. Embed dmdscript, boom you can use javascript.
(I really want to revive a dmdscript D2 port to make this
even easier, but it isn't hard right now either.)
You can try where I stopped it's still on D source, though I should
probably upload that on github.
If you are serious about dmd I would recommend it, as I've spent weeks
to figure out proper try/catch/finally implementation and fix closures
that were broken.

Last thing I vaguely recall is building it with 2.055 or 2.056, and
moving deprecated parts of phobos into it.
Post by Adam D. Ruppe
What if you want to script in D? If you're GPL... embed
dmd front end too.
Make D output JS, which is interpreted by D, calling
D apis....
Pretty insane, but you could script your app in D without
doing shared libraries or anything like that!
Indeed, but who knows ;)
Post by Adam D. Ruppe
Compared to cases 1-3 though, this is silly. Just a thought
that came to mind.
The web app use case is strong though. I think I'll actually
use this thing.
--
Dmitry Olshansky
Adam D. Ruppe
2012-02-29 19:40:30 UTC
Permalink
On Wednesday, 29 February 2012 at 19:10:27 UTC, Dmitry Olshansky
Post by Dmitry Olshansky
If you are serious about dmd I would recommend it, as I've
spent weeks to figure out proper try/catch/finally
implementation and fix closures that were broken.
Indeed, I still have a copy of your zip from before.

I tried to do it too, but I never got a lot of things
working quite right; it'd sometimes crash, I replaced the
AAs with a linear lookup since I didn't get that working
right either.

Your version worked well, as I recall.


But on dmdscript vs v8, v8 is faster, but I'm not too
concerned about speed.

A couple big advantages dmdscript has are:

a) I expect it will be easier to integrate in D apps

b) I already know its source code, so if I want to hack new
things on to the language, it won't be a big todo.

c) license is a little more permissive.



The big one though is familiarity with the source.
Dmitry Olshansky
2012-02-29 19:46:38 UTC
Permalink
Post by Adam D. Ruppe
Post by Dmitry Olshansky
If you are serious about dmd I would recommend it, as I've spent weeks
to figure out proper try/catch/finally implementation and fix closures
that were broken.
Indeed, I still have a copy of your zip from before.
I tried to do it too, but I never got a lot of things
working quite right; it'd sometimes crash, I replaced the
AAs with a linear lookup since I didn't get that working
right either.
I ended up using hacked RandAA by David Simcha, it works quite well.
It's a somewhat slow on reads comapred to d's native one, but sure it's
more stable ;)
Post by Adam D. Ruppe
Your version worked well, as I recall.
But on dmdscript vs v8, v8 is faster, but I'm not too
concerned about speed.
a) I expect it will be easier to integrate in D apps
b) I already know its source code, so if I want to hack new
things on to the language, it won't be a big todo.
c) license is a little more permissive.
The big one though is familiarity with the source.
Agreed, it's very clean and lean for full interpreter (not to mention
built-ins).
--
Dmitry Olshansky
Mikael Lindsten
2012-03-01 07:46:08 UTC
Permalink
2012/2/29 Adam D. Ruppe <destructionator at gmail.com>
Post by Adam D. Ruppe
4) This is an insane idea, but one that came to mind.
I'm testing this by piping the generated JS into
dmdscript.
dmd runs insanely fast when compiling this code. Phobos
is kinda slow to compile, but you don't have to use it
here. Write D1 style code and dmd is blink of an eye.
dmdscript is reasonably fast too.
Suppose you're writing an app and you want a scripting
extension. Embed dmdscript, boom you can use javascript.
(I really want to revive a dmdscript D2 port to make this
even easier, but it isn't hard right now either.)
What if you want to script in D? If you're GPL... embed
dmd front end too.
Make D output JS, which is interpreted by D, calling
D apis....
Pretty insane, but you could script your app in D without
doing shared libraries or anything like that!
Being mainly a web developer, I think this project of yours is really
exciting!

Also, being a fan of embedding JS into Java applications using their
ScriptingEngine API, I absolutely don't think number 4 is an insane idea. I
think it's a great idea!

I wish I had more time (and D knowledge!) to contribute.. for now I'm just
cheering!


/ Mikael
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d-announce/attachments/20120301/f3aaf9a9/attachment.html>
Andrei Alexandrescu
2012-03-01 17:35:02 UTC
Permalink
Post by Adam D. Ruppe
Sorry if I sent twice, it is so easy to hit the
wrong button on things.
So the idea is to make an entire subset of D convertible to Javascript?
Yeah, and I'm pretty much there - I just built a
little sort program with std.algorithm to it, which
is pretty cool.
Saw that - pretty amazing.

The motivation sounds great. I think one area of focus going forward
might be defining precisely the subset of D supported (e.g. I suppose
pointer semantics would be difficult). I presume most of Safe D would be
supported, but there's no formal definition of that either :o). Si this
area is ripe for development.


Andrei
Adam D. Ruppe
2012-03-01 19:13:50 UTC
Permalink
On Thursday, 1 March 2012 at 17:35:02 UTC, Andrei Alexandrescu
Post by Andrei Alexandrescu
The motivation sounds great. I think one area of focus going
forward might be defining precisely the subset of D supported
(e.g. I suppose pointer semantics would be difficult).
Right. I'm not sure exactly what is and is not @safe myself,
but I think *most* of it is realistic.

goto and pointers are the questionable ones right now. They
are solvable, but are they solvable in a way that I'm willing
to do? I don't want a while() { switch() { } } thing; the
code should look like javascript, not assembly.

Some integer semantics might be hard too. ubyte is ok, but byte
is different because 127+1 isn't as simple as x & 0xff

I'll have to think about that. Again, it surely *can*
be done, but I'd rather than an error than it generating
horribly inefficient javascript for simple operations.


But, everything else I've considered either already works
or is solvable with a little more time. It helps a lot
that dmd lowers a lot of the fancier things into simple
C-like constructs for me.


I just got scope guards working a few minutes ago, so
destructors can't be far behind.... then some bugs
on struct, and int math, goto, and pointer are the only
big rough spots left.


At least that I've thought of so far!
Bill Baxter
2012-03-01 19:49:13 UTC
Permalink
Post by Adam D. Ruppe
Some integer semantics might be hard too. ubyte is ok, but byte
is different because 127+1 isn't as simple as x & 0xff
I'll have to think about that. Again, it surely *can*
be done, but I'd rather than an error than it generating
horribly inefficient javascript for simple operations.
Might TypedArrays help you implement some number type semantics?
http://www.khronos.org/registry/typedarray/specs/latest/

--bb
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d-announce/attachments/20120301/118b085b/attachment-0001.html>
Adam D. Ruppe
2012-03-01 20:16:34 UTC
Permalink
Post by Bill Baxter
Might TypedArrays help you implement some number type semantics?
Yeah, I think so. I do have compatibility concerns though;
it'd be a pity of something taking a ubyte means it doesn't
work in IE8 anymore.

I'll have to play with it though.
Nick Sabalausky
2012-03-02 05:56:06 UTC
Permalink
"Adam D. Ruppe" <destructionator at gmail.com> wrote in message
Post by Adam D. Ruppe
but I'd rather than an error than it generating
horribly inefficient javascript for simple operations.
You make it sound as if there's another kind of JS.
Adam D. Ruppe
2012-03-02 14:38:27 UTC
Permalink
Post by Nick Sabalausky
You make it sound as if there's another kind of JS.
Horribly inefficient relative to the environment :P

I just don't want 100 kb of crap to download just to
write a hello world.

A lot of people prefer to use gzipped sizes, but I don't
because the browser still has to parse the whole thing,
and that takes time after the download, even if you don't
actually run any of it.

(On some browsers, it parses it again on every page load!)


This generated D code gzips very, very well, but I still
want to keep it small in general for general speed.

The fastest code is no code at all. Less to parse, less
to run.
Nick Sabalausky
2012-03-02 18:26:21 UTC
Permalink
"Adam D. Ruppe" <destructionator at gmail.com> wrote in message
Post by Adam D. Ruppe
Post by Nick Sabalausky
You make it sound as if there's another kind of JS.
Horribly inefficient relative to the environment :P
I just don't want 100 kb of crap to download just to
write a hello world.
Heh, yea. That's why, even though I use Haxe, I don't use it for generating
JS (unless I wanted to do a Flash-style HTML5/canvas thing).
Post by Adam D. Ruppe
A lot of people prefer to use gzipped sizes, but I don't
because the browser still has to parse the whole thing,
and that takes time after the download, even if you don't
actually run any of it.
(On some browsers, it parses it again on every page load!)
This generated D code gzips very, very well, but I still
want to keep it small in general for general speed.
The fastest code is no code at all. Less to parse, less
to run.
Suggestion: Allow all D features even if it
requires...inefficient-er...boilerplate, BUT then have a system similar to
@safe/@trusted/@system (or maybe just a "pragma(SimpleJS)") so a developer
can selectively turn on "Disallow any D features that would result in
extra-inefficient JS output" at the module-level (and/or whatever other
granularity @safe works on).
Adam D. Ruppe
2012-03-02 20:03:08 UTC
Permalink
Post by Nick Sabalausky
Suggestion: Allow all D features even if it
requires...inefficient-er...boilerplate, BUT then have a system
[...]
Eh. A problem there is those pragmas or whatever would be
unrecognized by the real dmd. A command line switch, maybe,
though.

But on pragmas, I have extern(js) and pragma(no_js_output),
but I want to keep them hidden inside the library modules.

Even if you version() something out, if dmd's lexer doesn't
understand it, it won't compile under the normal thing. This
breaks the benefit of same code on both sides.

But, version(generating_js) import something; always works.


That's about as fine-grained as I think it should be.



But, on this stuff, if it is there, I think it is ok to
use it. The key though is to not pay for what you don't use.


The gcfunctions helper app (in src/test/tools) acts like a
static linker here, cutting out unreferenced functions and
variables.


The library now can define a whole mess of functions, and
if you don't use them, they get stripped out of the final
file.


The key is then: a) not referencing stuff in a hidden fashion;
make sure typical D code is still small and b) minimizing
interdependencies, so pulling in one function doesn't pull
in a whole package.



This is something that's generally desirable in regular D,
too (for the same reason, even) so it is I think a good path.
Nick Sabalausky
2012-03-03 05:56:44 UTC
Permalink
"Adam D. Ruppe" <destructionator at gmail.com> wrote in message
Post by Adam D. Ruppe
Post by Nick Sabalausky
Suggestion: Allow all D features even if it
requires...inefficient-er...boilerplate, BUT then have a system [...]
Eh. A problem there is those pragmas or whatever would be
unrecognized by the real dmd. A command line switch, maybe,
though.
I thought unrecognized pragmas were supposed to just be ignored? (Or maybe I
have it backwards?)
Jacob Carlborg
2012-03-03 12:29:25 UTC
Permalink
"Adam D. Ruppe"<destructionator at gmail.com> wrote in message
Post by Adam D. Ruppe
Post by Nick Sabalausky
Suggestion: Allow all D features even if it
requires...inefficient-er...boilerplate, BUT then have a system [...]
Eh. A problem there is those pragmas or whatever would be
unrecognized by the real dmd. A command line switch, maybe,
though.
I thought unrecognized pragmas were supposed to just be ignored? (Or maybe I
have it backwards?)
No, they're not:

"Compilers must diagnose an error for unrecognized Pragmas, even if they
are vendor specific ones. This implies that vendor specific pragmas
should be wrapped in version statements".

http://dlang.org/pragma.html
--
/Jacob Carlborg
Daniel Murphy
2012-03-03 13:26:50 UTC
Permalink
"Jacob Carlborg" <doob at me.com> wrote in message
Post by Jacob Carlborg
Post by Nick Sabalausky
I thought unrecognized pragmas were supposed to just be ignored? (Or maybe I
have it backwards?)
"Compilers must diagnose an error for unrecognized Pragmas, even if they
are vendor specific ones. This implies that vendor specific pragmas should
be wrapped in version statements".
http://dlang.org/pragma.html
--
/Jacob Carlborg
There's a switch to ignore them.
Jacob Carlborg
2012-03-03 12:10:45 UTC
Permalink
Post by Adam D. Ruppe
Post by Nick Sabalausky
You make it sound as if there's another kind of JS.
Horribly inefficient relative to the environment :P
I just don't want 100 kb of crap to download just to
write a hello world.
A lot of people prefer to use gzipped sizes, but I don't
because the browser still has to parse the whole thing,
and that takes time after the download, even if you don't
actually run any of it.
(On some browsers, it parses it again on every page load!)
This generated D code gzips very, very well, but I still
want to keep it small in general for general speed.
The fastest code is no code at all. Less to parse, less
to run.
No, we don't want to do it like Dart:

https://gist.github.com/1277224

17260 lines of code for Hello World.
--
/Jacob Carlborg
Adam D. Ruppe
2012-03-03 16:40:31 UTC
Permalink
Post by Jacob Carlborg
17260 lines of code for Hello World.
Wow. I thought I was a bit on the bloated side with
~100 lines of boilerplate (before running the unused
function stripper).

$ ../dmd -md object.d
DMD v2.058 DEBUG
$ wc object.js
108 472 11843 object.js



Then again, when giant things like jQuery is considered
a "necessity" when I get by just fine with my 10 KB
(source, not minified, not gzipped) custom library,
if even that, it shows there's a big disconnect between
me and most other web people nowadays.
James Miller
2012-03-04 00:05:12 UTC
Permalink
Post by Adam D. Ruppe
Post by Jacob Carlborg
17260 lines of code for Hello World.
Wow. I thought I was a bit on the bloated side with
~100 lines of boilerplate (before running the unused
function stripper).
$ ../dmd -md object.d
DMD v2.058 DEBUG
$ wc object.js
?108 ? 472 11843 object.js
Then again, when giant things like jQuery is considered
a "necessity" when I get by just fine with my 10 KB
(source, not minified, not gzipped) custom library,
if even that, it shows there's a big disconnect between
me and most other web people nowadays.
Hmm, does your DOM library compile with this? Also, is it smaller than
jQuery? And how easy would it be to make it work with the browser dom?

This is mostly because I pretty much use jQuery for AJAX and Dom
manipulation, everything is just extras.

--
James Miller
Adam D. Ruppe
2012-03-02 17:20:20 UTC
Permalink
Here's one of the nicer things to do:

http://arsdnet.net/dtojs/game.d
http://arsdnet.net/dtojs/game.html

we can do little browser games in D.

If you look at game.js:
http://arsdnet.net/dtojs/game.js

you can see it is similar in size to the original
D file (this is after running tools/gcfunctions and
tools/mangledown on it; before them, it was 21 KB).

I just quickly whipped this together, so it isn't
much of a game - you just move your thing around.
Use keys a,d, and w to control it.


Not much to it, and writing this in Javascript would
have been easy enough, but even for this trivial thing,
a few D nicieties came through:

1) I typo'd one of the method names. D caught it instantly.

2) The degrees thing is supposed to be a user defined literal..
but it didn't actually work like that (it outputted functions
that returned the literals!) I consider this a bug in the
converter.

3) The click event handler is a little more succicent than the
same in Javascript would be.

4) The switch. Two nice features of D here that JS lacks:

a) "case 'A':" comes out as "case 65:". The key code is a
number, which is not equal to 'A' in Javascript!

A lot of sites have tables for this, but it is just ascii,
so 'A' works well. In D.

b) the comma on case is a bit shorter than the same in JS.
D is better at this short, dynamic stuff than JS itself
if you ask me - just look at the beauty of my server side
dom.d compared to JS.




But, it also shows that D->JS isn't a magic bullet.


1) This won't work on IE8, since it doesn't have the canvas thing
nor addEventListener. (The latter could be emulated in a
library,
though, with exactly the same syntax too.)

2) It runs smoothly on IE9, but sucks my butt on Firefox 9 on the
same computer (my little laptop).

It is still javascript when it runs, so speed boosts are
limited
by that; if the browser is slow, using D won't help much.

3) Obviously, it won't magically turn on people's javascript
either.
But, same language client+server means it is that much less
work to make nice fallbacks (e.g. proper validation).

BTW speaking of validation, I'm pondering if scope(failure)
could make elegant code for that...



But, hey, I'm calling it a win. The suckage of browsers
is a reality regardless of the language.
Nick Sabalausky
2012-03-02 21:11:49 UTC
Permalink
"Adam D. Ruppe" <destructionator at gmail.com> wrote in message
Post by Adam D. Ruppe
http://arsdnet.net/dtojs/game.d
http://arsdnet.net/dtojs/game.html
we can do little browser games in D.
http://arsdnet.net/dtojs/game.js
you can see it is similar in size to the original
D file (this is after running tools/gcfunctions and
tools/mangledown on it; before them, it was 21 KB).
I just quickly whipped this together, so it isn't
much of a game - you just move your thing around.
Use keys a,d, and w to control it.
Not much to it, and writing this in Javascript would
have been easy enough, but even for this trivial thing,
1) I typo'd one of the method names. D caught it instantly.
2) The degrees thing is supposed to be a user defined literal..
but it didn't actually work like that (it outputted functions
that returned the literals!) I consider this a bug in the converter.
3) The click event handler is a little more succicent than the
same in Javascript would be.
a) "case 'A':" comes out as "case 65:". The key code is a
number, which is not equal to 'A' in Javascript!
A lot of sites have tables for this, but it is just ascii,
so 'A' works well. In D.
b) the comma on case is a bit shorter than the same in JS.
D is better at this short, dynamic stuff than JS itself
if you ask me - just look at the beauty of my server side
dom.d compared to JS.
But, it also shows that D->JS isn't a magic bullet.
1) This won't work on IE8, since it doesn't have the canvas thing
nor addEventListener. (The latter could be emulated in a library,
though, with exactly the same syntax too.)
2) It runs smoothly on IE9, but sucks my butt on Firefox 9 on the
same computer (my little laptop).
It is still javascript when it runs, so speed boosts are limited
by that; if the browser is slow, using D won't help much.
3) Obviously, it won't magically turn on people's javascript either.
But, same language client+server means it is that much less
work to make nice fallbacks (e.g. proper validation).
BTW speaking of validation, I'm pondering if scope(failure)
could make elegant code for that...
But, hey, I'm calling it a win. The suckage of browsers
is a reality regardless of the language.
Yea, that's pretty cool. The *one* nice thing about modern JS is that is can
kill off Flash. Of course, it's still not a partucularly good approach, but
at least it's an improvement over Flash.

Your demo there reminds me of an awesome demoscene website around ten years
ago...umm "matt"-something-or-other. Shit, I can't remember, but it was like
a demoscene entry, but with the browser as the platform. Included one or two
DHTML games, and this was years before anyone had even heard of "canvas" or
"HTML5". Unfortunately, I don't think it's around anymore :(
Marco Leise
2012-03-01 16:27:03 UTC
Permalink
Post by Andrei Alexandrescu
Post by Adam D. Ruppe
https://github.com/downloads/adamdruppe/dtojs/dtojs.zip
[snip]
That's interesting. So the idea is to make an entire subset of D
convertible to Javascript?
What use cases do you have in mind?
Andrei
The visualizer I wrote for aichallenge.org had 3 versions:

- HTML 5 / JavaScript
- Java applet
- Java application

The source code was in JavaScript and executed in the Rhino JS engine for the Java versions. The applet was actually there to support Internet Explorer versions which suffered from a massive NIH syndrome when it came to HTML 5. So with those becoming a minority the remaining targets are the standalone application and the browser visualizer.
With D-to-JS I would have had the option to write the application in D using GtkD or similar GUI library with access to drawing functions that are similar to the HTML 5 Canvas, and then export the whole thing to JS. The obvious benefits are to me:

- Native efficiency (JS in Rhino in JVM used masses of memory and was slow as molasses)
- Type checking and compiler errors

The downside is that I would have missed the perfect JavaScript debugging support in the major browsers when working with D code. :)
Adam D. Ruppe
2012-03-01 05:20:45 UTC
Permalink
I probably should have been working today.... but instead
spent a good amount of time on this again.

New zip:

https://github.com/downloads/adamdruppe/dtojs/dtojs-0.3.zip

(I haven't cleaned up the github fork yet)

To give you an idea of what is working, check out
my tests.d file:

http://arsdnet.net/dtojs/tests.d

This compiles (raw) into this:
http://arsdnet.net/dtojs/tests.js

BTW, when compiling, be sure to put test/object.d
on your command line too, or the runtime functions
won't be present in your .js file!

23 KB (down to 11 KB if you run the included mangledown tool
on it. gcfunctions can often make a big difference, but not here,
since it removes what you don't use. A test that doesn't use
something is an incomplete test!)


I think I broke std.algorithm again :(, but fixed a lot of
other stuff. (it is the lambda generator in std.algorithm that
is breaking. The JS has the function, but it is nested too deep
and inaccessible to the actual algorithm.)



But, a lot of stuff works now, and the generated code isn't
half bad. I've started using more static type info to slightly
optimize it too, but only some basics.


One of the messiest things was try/catch. JS doesn't do
types like D, so I implemented it with a series of
if(dynamic_cast()), and ultimately rethrow if none matched.

A bit ugly, but it seems to pass the tests!

(The messiest compiler implementation so far is [0..$]. That
pesky dollar sign. In microd.c, you can see a couple global
variables there to hack things up. Poo. But, again, it works.)


Library wise, check out src/test/jslang and src/test/browser.
I tried for completeness there, but not full accuracy yet.

This gives free (no generated wrappers) access to regexps,
the array object, string functions, etc. as part of the
core language, and browser has things for the DOM, window,
history, location, canvas, style, json, ajax, etc. - all
just bindings to the native functions.



I'm to the point where I think I'm ready to write a program
with this thing!
Jacob Carlborg
2012-03-01 07:14:02 UTC
Permalink
Post by Adam D. Ruppe
I probably should have been working today.... but instead
spent a good amount of time on this again.
BTW, how do you fit D's class based object model in JavaScript's
prototype based object model?
--
/Jacob Carlborg
Adam D. Ruppe
2012-03-01 15:07:57 UTC
Permalink
Post by Jacob Carlborg
BTW, how do you fit D's class based object model in
JavaScript's prototype based object model?
Short answer is each D object in JS has a virtual
function array and implements array as properties
attached to the object. The JS constructor for the
object populates these arrays.

Virtual calls thus look like:
obj._virtual_table[call_num]();

instead of
obj.function();

It is similar in principle to how you'd implement
it in C.

Long answer:

A D class is written out like this:

function _d_class_NAME(requested_constructor) {
_d_class_object.call(this, null);
// repeat for all base classes through to Object
_d_class_baseclass.call(this, null);

this.virtual_function_table[index] = member_function;
// repeat for all virtual functions

/* BTW, I'm probably going to change this implementation but
it will have the same result */
this.implements = ["Object", "Interface_Name", "Base_Class",
"This_Class"];
// (these names are actually mangled in the real thing)


if(requested_constructor)
requested_constructor(this, arguments);
}

function member_function(arguments..., d_this) {
// implementation of the member function
}




Usage:

in D:
MyClass a = new MyClass();
a.final_function();
a.virtual_function();

in Javascript:
var a = new _d_class_MyClass(default_constructor);
// most functions are free functions, like they would be
implemented
// in C. You pass this as a final parameter:
MyClass_final_function(a);

// but virtual functions have to use the table:
a.virtual_function_table[0]();




The index into the virtual table is known by dmd ahead of
time, so plain integers are outputted.



If you override, what happens is the base class initializer
is called first, which creates its virtual functions.

Then, your class initializer simply overwrites that entry
in the table.

(Plain Javascript properties probably could have done this too,
with the base class being the prototype, but dmd already
has the infrastructure to do it C style, and getting the
Js names right in the presence of things like overloading
would have been harder to keep straight than a simple integer
index.)




Whether you access it through a base class, interface, or
whatever, the vtable is attached to the object, so it works.



The other thing you expect in classes is dynamic casting.
That's where the this.implements comes in.

If you write cast(Class) object; in D, it outputs
var n = __d_dynamic_cast(object, "Class");



The dynamic cast function is implemented in test/object.d as
a simple loop:

// given an object, should we allow the runtime cast to succeed?
// if no, return null.
Object __d_dynamic_cast(Object from, string to) {
if(from.__d_implements) {
foreach(s; from.__d_implements)
if(s == to)
return from;
return null; // it is a D object, but not of this class
}
// if in doubt, let it pass since we don't want to tie hands
// where the programmer knows what he is doing. I might
// change this since it isn't actually that good of an
idea.
// (there's always reinterpret_cast if you know you want
it)
return from;
}


But yeah, if the class name is in the implements list, go ahead
and return the object; the cast succeeds. If not, do null.



This is used in exception handling. In D, if you write:

try {
throw new Exception("not an error");
} catch(Error e) {
assert(0);
}


you expect the exception to keep flying, since Exception is not
an Error.

Javascript, though, doesn't have the same concept of types.

I implemented this like so:


try {
throw new _d_Exception(exception_string_constructor, "not an
error");
} catch(e) {
var was_exception_caught = false;
var e_as_error = _d_dynamic_cast(e, "Error");
if(e_as_error) {
was_exception_caught = true;
0 || _d_assert(...);
}
// repeat for other catch blocks, if present

if(!was_exception_caught);
throw e; // keep it going up the call stack
}



The dynamic cast lets the program know if we have the right
catch block, so it works like you expect it would in D.


(Javascript can do something similar with if(e instance of y),
but... I'm not 100% sure; I don't do this kind of JS often, but
I'm pretty sure instanceof only looks at the constructor - there's
no inheritance chain to look at. If we catch(Throwable), we want
Error, Exception, and all their subclasses in D.)




That initializer that sets up the vtbl also does things like
default value initialization, so int a; is == 0 like you
expect in D.


This got a little fun for the magical "null" word.

int[] a = null;
a ~= 3;

if we translated that as

var a = null;
a = a.concat(3); // fails, a is null

it is no good. JS null isn't the right type.


But, D's null knows what type it is! So, NullExp
looks like this:

if(type->ty == Taarray) // ass array
sink("{}"); // use an object literal as this null
else if(string)
sink("\"\"")
else if(array)
sink("[]");
else
sink("null");



Now, the JS variables are the right type when initialized
to D's null.

The trick will now be getting is null right... but meh
that confuses people in D itself due to implementation
details, so I think I'll just make (array is null)
mean (array === []) or something along those lines and
call it good enough.
Jacob Carlborg
2012-03-01 19:42:32 UTC
Permalink
Post by Adam D. Ruppe
Post by Jacob Carlborg
BTW, how do you fit D's class based object model in JavaScript's
prototype based object model?
Short answer is each D object in JS has a virtual
function array and implements array as properties
attached to the object. The JS constructor for the
object populates these arrays.
obj._virtual_table[call_num]();
instead of
obj.function();
It is similar in principle to how you'd implement
it in C.
Ok, I see. Thanks for the detailed explanation.
--
/Jacob Carlborg
Daniel Murphy
2012-03-01 08:01:03 UTC
Permalink
I love how this started as interesting and turned into awesome.

Web programming... might actually become non-horrible?
Adam D. Ruppe
2012-03-02 02:28:57 UTC
Permalink
Post by Daniel Murphy
Web programming... might actually become non-horrible?
hehe. I already found it ok though; I've been using
D on the server for... will be two years in a couple
weeks.

Javascript isn't bad if you use it sparingly, and
in the last year, my web.d server side thing has just
enough javascript to let me write less of it.

I just call server side functions in most the JS. I
went a little nuts on partial application to make it
nice looking; you pass arguments to the callback when
you make it.



But, it is nice to have this other stuff too. If I
have to do a browser game, definitely doing D now,
from top to bottom. Work wants ipad apps too...
I'll probably do them as downloadable browser things,
now in D!




Anyway, a few more hours on d to js today. I spent
the time working on struct semantics.


It is amazing how complicated structs are! Compared
to this, classes are just plain easy.


My tests file (which I need to run in real D to confirm
my thought here, but I think all my asserts are sane)
now passes including tests of struct.

http://arsdnet.net/dtojs/tests.d



I implement structs as Javascript Object()'s, but this
doesn't quite match what D expects.

1) JS Object are references, whereas D struct are value.
2) JS variables have indeterminate lifetimes
3) The JS language doesn't have block scoping like D.



(1) was a big mess, and I'm sure I don't have it right
yet (I know it is a lot less efficient than it could be).

My solution was to make all assignments do shallow copies,
including function call.

void t(MyStruct a) {}
t(a);

becomes

t(__d_struct_copy(a))


Worked for the basics. But, D structs are incredibly
complex monsters.

opAssign, postblit, copy constructors, blit initializers,
expression initializers, TOKconstruct - something I'm not
even sure what it actually is.

Well, I think I got it. Lots of filthy dirty code, but
it passed the test file.

I haven't tested struct constructors yet, but they are
relatively easy, just like class constructor, so I'm
confident it will work.



(2) and (3) go together: variable lifetime. D structs
die when they go out of scope, both on function
returns and exceptions.

dmd implemented this as a Scope followed by a Finally.

I ended up making it put try {} around the scope, and then
write out the finally {}.

dmd really did all the work already! And... finally works
in Javascript.


Amazing, we have struct destructors working like you expect.
Moreover, dmd implements scope(exit) the exact same way.

Boom, we have scope guards too.


To my surprise, scope(failure) and scope(success) Just Worked:
dmd set up a flag variable and automatically added it to
the appropriate places.


As far as I can tell, we have variable lifetime! (JS's garbage
collector is still a question, and some of the variables are
global - dmd loves the (var a, b) syntax, which is invalid so
I made var a in global scope. It is not set to null when done.)



Pretty cool. The majority of the language works correctly,
though there's a few hacks in there to make it happen.


I probably won't upload another zip until the weekend though.
Jacob Carlborg
2012-03-02 08:03:20 UTC
Permalink
Post by Adam D. Ruppe
Post by Daniel Murphy
Web programming... might actually become non-horrible?
As far as I can tell, we have variable lifetime! (JS's garbage
collector is still a question, and some of the variables are
global - dmd loves the (var a, b) syntax, which is invalid so
I made var a in global scope. It is not set to null when done.)
What do you mean with "dmd loves the (var a, b) syntax, which is invalid
so"?
--
/Jacob Carlborg
Daniel Murphy
2012-03-02 09:57:56 UTC
Permalink
"Jacob Carlborg" <doob at me.com> wrote in message
Post by Jacob Carlborg
Post by Adam D. Ruppe
Post by Daniel Murphy
Web programming... might actually become non-horrible?
As far as I can tell, we have variable lifetime! (JS's garbage
collector is still a question, and some of the variables are
global - dmd loves the (var a, b) syntax, which is invalid so
I made var a in global scope. It is not set to null when done.)
What do you mean with "dmd loves the (var a, b) syntax, which is invalid
so"?
CommaExp's containing Declarations
Jacob Carlborg
2012-03-02 10:49:47 UTC
Permalink
"Jacob Carlborg"<doob at me.com> wrote in message
Post by Jacob Carlborg
Post by Adam D. Ruppe
Post by Daniel Murphy
Web programming... might actually become non-horrible?
As far as I can tell, we have variable lifetime! (JS's garbage
collector is still a question, and some of the variables are
global - dmd loves the (var a, b) syntax, which is invalid so
I made var a in global scope. It is not set to null when done.)
What do you mean with "dmd loves the (var a, b) syntax, which is invalid
so"?
CommaExp's containing Declarations
Is he saying "var a, b, c;" is invalid JavaScript code?
--
/Jacob Carlborg
Daniel Murphy
2012-03-02 11:27:31 UTC
Permalink
"Jacob Carlborg" <doob at me.com> wrote in message
Post by Jacob Carlborg
Post by Daniel Murphy
CommaExp's containing Declarations
Is he saying "var a, b, c;" is invalid JavaScript code?
--
/Jacob Carlborg
It's invalid if it's a comma expression.

eg.

auto x = (auto a = 3, a);

Which dmd creates _everywhere_.
Alix Pexton
2012-03-02 09:33:54 UTC
Permalink
Post by Adam D. Ruppe
3) The JS language doesn't have block scoping like D.
Have you considered faking scopes in JS using anonymous functions?

----
var foo;

(function(a, b){
var foo; // not the same as the foo outside the func!
// do stuff
}(x, y)); // invoke immediately with needed arguments from outer scope

----

by passing all the parameters to the anon func you get a speed increase
in the lookup on most JS platforms.

I don't think they are very pretty, but it is sometimes a useful technique.

A...
Adam D. Ruppe
2012-03-02 14:57:52 UTC
Permalink
Post by Alix Pexton
Have you considered faking scopes in JS using anonymous
functions?
Yeah, though right now I'm trusting the D compiler to
keep it straight, and it is doing a pretty good job
while being really simple to code.

What happens is all the local variables are mangled
with respect to their full scope too (which leads to
ridiculously long, but unique names).

The D scope simply outputs its own code:

D:
{ // create a scope
int a = 10;
}
int a = 20; // the old a is out of scope, so we can do this

Javascript:
var _D_inner_a = 10; // not a real var name, just demo
var _D_outer_a = 20; // new var


The inner variable is still in scope, so I doubt Javascript
garbage collects it, but thanks to the rules of D, it is
never used again.

But, if you use a struct with a destructor (or scope(exit)),
it generates this:

D:
{
MyStruct a;
}
MyStruct a;

Javascript:

try {
var _D_inner_A = new MyStruct();
}
finally {
MyStruct_destructor(_D_inner_A);
}
try {
var _D_outer_A = new MyStruct();
}
finally {
MyStruct_destructor(_D_outer_A);
}



And, in this case, Javascript's bizarre scoping
actually simplifies things.


In Javascript, when you write "var x = y;" in the
middle of a function, the way it really works is
it adds a "var x;" to the top of the function,
and leaves "x = y;" in hte middle.


You write:
function test() {
if(something_here()) {
var a = 10;
}
a++;
}

Javascript acts as if you wrote:

function test() {
var a;
if(something_here()) {
a = 10;
}
a++;
}


With our try/finally (that dmd generates, mostly; I didn't
have to do much to make this work), the var declartion
in the try being hoisted up top means we can be sure it
works correctly in the finally, too.




But, with regard to the D scoping, dmd mangles the names
to make sure you don't reference anything that's out of
scope accidentally by giving them unique names.




This hoisting behavior is the proper solution to the
CommaExp declarations mentioned previously, where
dmd likes to write: foo( (var a = 10, a) ) and the
sort.


Currently, I put the var a; in global scope, leaving
just (a=10,a) in the expression. This is legal Javascript,
and should be ok due to unique names, but it pollutes the globals.


If I add a way to instead put those var declarations in
function scope, it is cleaner - no globals - and the same
thing Javascript itself would do anyway!


I'll have to redo the string buffering to make that though,
so it will take some code to do it. Dumping it in the global
was simple to implement with what was already there.
Post by Alix Pexton
I don't think they are very pretty, but it is sometimes a
useful technique.
heh, same with mangled names :)
Daniel Murphy
2012-03-03 00:56:46 UTC
Permalink
"Adam D. Ruppe" <destructionator at gmail.com> wrote in message
Post by Adam D. Ruppe
If I add a way to instead put those var declarations in
function scope, it is cleaner - no globals - and the same
thing Javascript itself would do anyway!
I'll have to redo the string buffering to make that though,
so it will take some code to do it. Dumping it in the global
was simple to implement with what was already there.
Btw, in VarDeclaration::toMicroD you're using microd_decl23 as the sink,
which results in all var declarations getting doubled. The problem with
globals not getting default initialized is here too, it's only using
explicit initializers. Something like this should work:


// set sink to be one of the normal buffers, not a tee

sink(" = ");
if (init)
init->toMicroD(sink);
else
type->defaultInit(0)->toMicroD(sink);
sink(";\n");
Adam D. Ruppe
2012-03-03 01:09:37 UTC
Permalink
Awesome, it does! Thanks.
Jacob Carlborg
2012-03-03 12:12:51 UTC
Permalink
Post by Adam D. Ruppe
Post by Alix Pexton
Have you considered faking scopes in JS using anonymous functions?
Yeah, though right now I'm trusting the D compiler to
keep it straight, and it is doing a pretty good job
while being really simple to code.
What happens is all the local variables are mangled
with respect to their full scope too (which leads to
ridiculously long, but unique names).
Wouldn't you save a lot of characters by properly scoping the variables
instead of using unique names? The compile JavaScript code would also be
more readable.
--
/Jacob Carlborg
Alix Pexton
2012-03-03 12:18:10 UTC
Permalink
Post by Jacob Carlborg
Post by Adam D. Ruppe
Post by Alix Pexton
Have you considered faking scopes in JS using anonymous functions?
Yeah, though right now I'm trusting the D compiler to
keep it straight, and it is doing a pretty good job
while being really simple to code.
What happens is all the local variables are mangled
with respect to their full scope too (which leads to
ridiculously long, but unique names).
Wouldn't you save a lot of characters by properly scoping the variables
instead of using unique names? The compile JavaScript code would also be
more readable.
and potentially faster!

A...
Adam D. Ruppe
2012-03-03 16:29:24 UTC
Permalink
Post by Jacob Carlborg
Wouldn't you save a lot of characters by properly scoping the
variables instead of using unique names?
There's no such thing as proper scoping in Javascript.

The next best thing is the nested functions, but that's
really just trading one poison for another.


D mangled names do a lot more than scoping, too, anyway.
Mangled names overload properly:

void a(int, int);
void a(int, string);

a(1, "one"); // which one gets called?


With dmd's name mangling, it Just Works.


Now, there might be something to gain by using prettier
local variable names, but it is a lot of extra work and
IMO the benefit is still very small.


Note that local variables are still local variables
95% of the time (and the other 5% is a bug that I'm
hoping to fix today), so its already scoped almost
as well as it can be on the function level.



The biggest benefit is readability and size. Size is handled
by running it through a string replacer (tools/mangledown.d).

Readability is a nice gain, but not an essential one I think;
it is readable right now if you want to.
Adam D. Ruppe
2012-03-03 16:49:21 UTC
Permalink
Post by Adam D. Ruppe
There's no such thing as proper scoping in Javascript.
Let me expand a bit. consider this D:

if(1) {
int a = 3;
}

In JS, right now, that'd output:

if(1) {
var mangled_a = 3;
}

which, to the interpreter, is:

var mangled_a;
if(1) {
mangled_a = 3;
}

thanks to declaration hoisting.


If you want it to be scoped literally like D,
it'd look more like this:

if(1) {
function() {
var a = 3;
}();
}


I really doubt that'd help performance. Another option
is to reuse declarations:

if(1) {
int a = 0;
}
string a = "";

could become:

var a;
if(1) {
a = 0;
}
a = ""; // we know the old a is out of scope, so we'll reuse it


but I don't see a big benefit there either. Now, the JS
compiler will definitely see a as a dynamically typed var,
and may not be able to do the same optimizations it could
if it had a consistent type.


When you consider the bug-pronedness of me doing this instead
of relying on dmd's well debugged mangling process to do it
all for me, I really think it is a net loss, despite the
slightly more readable names.



Oh another thing: global variables in D are module scoped.
The mangledness again handles that for me. Just another
bug opportunity.



Perhaps a smarter helper tool could make pretty names, but
I don't want to put it in the compiler.
Andrej Mitrovic
2012-03-04 00:09:01 UTC
Permalink
Post by Adam D. Ruppe
Oh another thing: global variables in D are module scoped.
Could export help?

Jacob Carlborg
2012-03-03 18:07:10 UTC
Permalink
Post by Adam D. Ruppe
Post by Jacob Carlborg
Wouldn't you save a lot of characters by properly scoping the
variables instead of using unique names?
There's no such thing as proper scoping in Javascript.
The next best thing is the nested functions, but that's
really just trading one poison for another.
Ok, I see.
Post by Adam D. Ruppe
D mangled names do a lot more than scoping, too, anyway.
void a(int, int);
void a(int, string);
a(1, "one"); // which one gets called?
With dmd's name mangling, it Just Works.
Well, functions are different.
Post by Adam D. Ruppe
Now, there might be something to gain by using prettier
local variable names, but it is a lot of extra work and
IMO the benefit is still very small.
Note that local variables are still local variables
95% of the time (and the other 5% is a bug that I'm
hoping to fix today), so its already scoped almost
as well as it can be on the function level.
The biggest benefit is readability and size. Size is handled
by running it through a string replacer (tools/mangledown.d).
Readability is a nice gain, but not an essential one I think;
it is readable right now if you want to.
--
/Jacob Carlborg
Robert Clipsham
2012-03-01 16:29:09 UTC
Permalink
Post by Adam D. Ruppe
I probably should have been working today.... but instead
spent a good amount of time on this again.
https://github.com/downloads/adamdruppe/dtojs/dtojs-0.3.zip
(I haven't cleaned up the github fork yet)
To give you an idea of what is working, check out
http://arsdnet.net/dtojs/tests.d
http://arsdnet.net/dtojs/tests.js
BTW, when compiling, be sure to put test/object.d
on your command line too, or the runtime functions
won't be present in your .js file!
23 KB (down to 11 KB if you run the included mangledown tool
on it. gcfunctions can often make a big difference, but not here,
since it removes what you don't use. A test that doesn't use
something is an incomplete test!)
I think I broke std.algorithm again :(, but fixed a lot of
other stuff. (it is the lambda generator in std.algorithm that
is breaking. The JS has the function, but it is nested too deep
and inaccessible to the actual algorithm.)
But, a lot of stuff works now, and the generated code isn't
half bad. I've started using more static type info to slightly
optimize it too, but only some basics.
One of the messiest things was try/catch. JS doesn't do
types like D, so I implemented it with a series of
if(dynamic_cast()), and ultimately rethrow if none matched.
A bit ugly, but it seems to pass the tests!
This is really cool! It would be quite interesting to run the dmd
testsuite through it and see how much passes. Same goes for phobos
unittests (obviously both of these would fail for system stuff like
inline asm...)

I'd also be interested in some benchmarks (eg std.algorithm.sort vs
Array.sort), but that seems a bit pointless really. Might be interesting
to throw in some optimisations when translating though (though you're
doing some of these already!)

Interesting idea:

version(JavaScript) asm
{
/* Well... it's not really asm, but it's
as close as you could get with a javascript backend :p */
document.write("Oh look, inline javascript D-:");
}

Perhaps it would be better to have a dedicated function for that though.
--
Robert
http://octarineparrot.com/
Adam D. Ruppe
2012-03-01 16:43:08 UTC
Permalink
Post by Robert Clipsham
Perhaps it would be better to have a dedicated function for
that though.
eval() :)

I considered doing asm {} for javascript, but that'd be a
pretty invasive change to the compiler, so I decided against
it; I want to keep most the changes as simple as possible.

One possibility would be a special function, let's call it
static_eval, that takes a string but instead of being a
function call, simple pastes the string itself into the
js file.

But, I haven't really wanted it yet! All the functions I
want have been implementable in relatively plain D (with
the addition of the __js_keywords in some places), except
foreach on associative arrays.

I had to hardcode that function, since there's no way to
represent for(i in obj) on the low level.



For phobos btw, I haven't decided how to run with that yet.
My first thought was to implement my own version - test/std
shows this - that emulates the interface using native JS
functions where possible.

That will be hard to keep up to date, and causes conflicts
if you want to borrow a little from the real Phobos. So
eh, I don't know yet.
Jean-Bernard Pellerin
2012-03-02 04:26:46 UTC
Permalink
This will go nicely with the web framework I'm building in D. I'm
borrowing heavily from silverlight. Here's a teaser (sorry,
neglected to comment the code...)

Here's a sample code file (CGI script for apache, I'm new to
these web technologies):
http://pastebin.com/SpfmfpmS

and here's what the resulting site looks like, sorry for the
image quality

before pressing the button:
Loading Image...
after:
Loading Image...
Notice how I clicked a different tab (woot)

It's my first time using HTML, CSS, or JS, so it's a bit rough.
But I learn it as I go along, to perform the code generation.

A whole lot of really neat CTFE and mixins went into having the
Control classes and Factory working as smoothly as they do. I'll
publish it on my blog once it's built (I want to showcase
darklight with a blog written in darklight) :D

But I just noticed you have a whole suite of D web code, I'll
have to look into it.

Thanks for all the hard work you've put into D, it's quite a feat.
Loading...