February 08, 2007
Yauheni Akhotnikau wrote:
>> The main difficulty is if the DSL needs to access symbols in the rest of the D code.
> 
> I agree.
> But how do you think do such things in the current approach?

int i = 4;
mixin("writefln(i)");

will print:

4
February 08, 2007
Yauheni Akhotnikau wrote:
> I'm use Ruby a lot and much metaprogramming things done via creating strings with Ruby code and evaluating it by various 'eval' methods. It is very simple method -- easy in writting, debugging and testing. And there isn't two different Ruby -- only one language.

That's possible because Ruby is interpreted - its compilation environment is also the execution environment.

But D is a statically compiled language, so there's a distinction between a compile time variable, and a runtime variable.
February 08, 2007
On Thu, 08 Feb 2007 10:06:04 +0300, Walter Bright <newshound@digitalmars.com> wrote:

> Yauheni Akhotnikau wrote:
>>> The main difficulty is if the DSL needs to access symbols in the rest of the D code.
>>  I agree.
>> But how do you think do such things in the current approach?
>
> int i = 4;
> mixin("writefln(i)");
>
> will print:
>
> 4

I understand that :)
But suppouse than string "writefln(i)" has been produced by some DSL transformator:

 int i = 4;
 mixin( ProduceWritefln("i") );

The content of ProduceWritefln() need no access to variable i -- it makes some string which transformed to D code only in mixin(), not in ProduceWritefln. So the main task of ProduceWritefln is manipulating of string without access to any existed D code.

So my point is to allow to ProduceWritefln be ordinary D code which executed at compilation time.

-- 
Regards,
Yauheni Akhotnikau
February 08, 2007
Charles D Hixson wrote:
...
> Forth is very similar to LISP, only with a simpler grammar. I.e., the grammar is simple serial execution, with  certain words (those marked immediate) able to manipulate the input stream to determine what will be the next in order.

I think the comparison to LISP is a good way to think about forth:

1. Write a lisp program, but put the function name after its arguments
   for every expression.  This will be hard to read but by following
   the parenthesis you can just barely tell what is happening.

2. Remove all the parenthesis.

At least 90% of the time, if you remove a symbol from a valid forth program, you get a valid (but incorrect) forth program -- there is almost zero redundancy in the language so errors are almost never detectable at compile time, which means you should write short clear functions.

But the central feature of FORTH is that the compiler and runtime can be made mind-bogglingly small.  I think the run time speed for a naive interpretation is probably somewhere between C and interpreted bytecode.

From this page about tiny4th: http://www.seanet.com/~karllunt/tiny4th

"The run-time engine takes up less than 1K of code space and the p-codes are so dense that you can get a lot of robot functionality in just 2K."

Of course, that's a compiler; an interactive language environment can be used for prototyping (like with lisp) and that will run a bit bigger.

Kevin
February 08, 2007
Yauheni Akhotnikau wrote:
> On Thu, 08 Feb 2007 10:06:04 +0300, Walter Bright <newshound@digitalmars.com> wrote:
> 
>> Yauheni Akhotnikau wrote:
>>>> The main difficulty is if the DSL needs to access symbols in the rest of the D code.
>>>  I agree.
>>> But how do you think do such things in the current approach?
>>
>> int i = 4;
>> mixin("writefln(i)");
>>
>> will print:
>>
>> 4
> 
> I understand that :)
> But suppouse than string "writefln(i)" has been produced by some DSL transformator:
> 
>  int i = 4;
>  mixin( ProduceWritefln("i") );
> 
> The content of ProduceWritefln() need no access to variable i -- it makes some string which transformed to D code only in mixin(), not in ProduceWritefln. So the main task of ProduceWritefln is manipulating of string without access to any existed D code.
> 
> So my point is to allow to ProduceWritefln be ordinary D code which executed at compilation time.

I see your point, but passing arguments "by name", which is what your example does, means the function has no access to whatever that name is - such as its type, size, etc.
February 08, 2007
On Thu, 08 Feb 2007 10:08:29 +0300, Walter Bright <newshound@digitalmars.com> wrote:

> Yauheni Akhotnikau wrote:
>> I'm use Ruby a lot and much metaprogramming things done via creating strings with Ruby code and evaluating it by various 'eval' methods. It is very simple method -- easy in writting, debugging and testing. And there isn't two different Ruby -- only one language.
>
> That's possible because Ruby is interpreted - its compilation environment is also the execution environment.
>
> But D is a statically compiled language, so there's a distinction between a compile time variable, and a runtime variable.

Yes, I undertand that. But that is my point: in Ruby there are three steps:
1) use ordinal Ruby code to produce string with another ordinal Ruby code;
2) translation of string with ordinal Ruby code into bytecode;
3) run of bytecode.

In D we now have steps 2) and 3) implemented: step 2) is a compilation phase. The question is: how to perform step 1)?

If it is necessary to use special constructs to build strings with ordinal D code then I will prefer to use pre-compile-time generation with help of external tools.

For example, in last four years I have used home-made serialization framework for C++. It requires special description of serializable type in special Data Definition Language, like this:

{type {extensible}	handshake_t
  {attr	m_version {of oess_1::uint_t}}
  {attr	m_client_id {of std::string}}

  {extension
    {attr  m_signature
       {of signature_setup_t}
       {default {c++ signature_setup_t()}}
    }
    {attr  m_compression
       {of compression_setup_t}
       {default {c++ compression_setup_t()}}
    }

    {extension
       {attr m_traits
          {stl-map {key oess_1::int_t}}
          {of handshake_trait_shptr_t}
          {default {c++ std::map< int, handshake_trait_shptr_t >()}
              {present_if {c++ m_traits.size()}}
          }
       }
    }
  }
}

The library for parsing such s-expression is about 7K lines in C++ and 2.5K lines in Ruby. Comparable size it will have in D. But, if I want to use such DDL as DSL in mixin expression I must write two version of s-expression parsing -- for run-time and compile-time :(

But if I can use ordinal D code at compile time then the situation is much better.

-- 
Regards,
Yauheni Akhotnikau
February 08, 2007
>>  So my point is to allow to ProduceWritefln be ordinary D code which executed at compilation time.
>
> I see your point, but passing arguments "by name", which is what your example does, means the function has no access to whatever that name is - such as its type, size, etc.

Yes, but here we have two alternative approaches:

1) generation of strings with D code without access to addition information (my sample above). This is approach largely used in Ruby metaprogramming. And this is very useful approach in many situations, i.e. it is not an ideal solution, but useful (in my expirience);

2) manipulation of syntax tree in compilation phase, where the macros code has access to all information about programm's symbols (identifiers, types and so on). This approach is used in Nemerle, but there macroses received as input not string, but ordinal Nemerle code.

So my problem with understanding role of new D constructs (mixin expressions and import expressions) is: if the Ruby's approach with string generation is not appropriate then how to get something like Nemerle's approach if we use strings in mixin expressions?

-- 
Regards,
Yauheni Akhotnikau
February 08, 2007
BCS wrote:
> Derek Parnell wrote:
>> On Wed, 07 Feb 2007 11:50:50 -0800, BCS wrote:
>>
>> So in your example above ...
>>
>>   version(build) pragma(export_version, Foo, Bar);
>>
> 
> Cool, but I think that would be
> 
>  version(Foo) pragma(export_version, Bar);

No, you need both version()s:
    version(build) version(Foo) pragma(export_version, Bar);
or
    version(Foo) version(build) pragma(export_version, Bar);

An unknown pragma is an error, so you need to put build-specific pragmas in a version(build).
February 08, 2007
Walter Bright wrote:
> Fixes many bugs, some serious.
> 
> Some new goodies.
> 
> http://www.digitalmars.com/d/changelog.html
> 
> http://ftp.digitalmars.com/dmd.1.005.zip

Wow, This is just sweet! Thanks, Walter! :D I'll see what kind of abuse can be done with the new mixin stuff ;)
Still, we must find a way to reduce the memory requirements of evaluating more complex templates - as at one point, they are going to contain pretty arbitrary code.


--
Tomasz Stachowiak
February 08, 2007
Kevin Bealer wrote:
> Charles D Hixson wrote:
> But the central feature of FORTH is that the compiler and runtime can be made mind-bogglingly small.  I think the run time speed for a naive interpretation is probably somewhere between C and interpreted bytecode.
> 
>  From this page about tiny4th: http://www.seanet.com/~karllunt/tiny4th
> 
> "The run-time engine takes up less than 1K of code space and the p-codes are so dense that you can get a lot of robot functionality in just 2K."

Before someone thinks, Forth is only a play-thing, see http://www.forth.com/

There are also excellent freeware versions around, f.ex.
http://win32forth.sourceforge.net/

There is even ans ANS / ISO standard for the language.

Andreas