www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - feature request: __ARGS__ for logging (cf __FILE__, __LINE__,

reply "timotheecour" <thelastmammoth gmail.com> writes:
One of the rare features I miss in C/C++ is stringification macro 
using "#x":

---
#include ...
#define DEBUG(x) disp_val(#x,x)
template<typename T>
void disp_val(const char*name, const T& x) {std::cout << name << 
"=" << x;}
int main(){
DEBUG(1+2); //will print 1+2=3 (and we can add line, file and 
func info)
ASSERT(1+2==4); //can also be defined such that it'll print 
1+2==4 failed...
}
---

In D, we have built-in assert message that'll print the failing 
expression "1+2==4 failed" in case of failure but that's about 
it: no further processing can be done on that message, and 
there's nothing we can do about the DEBUG(1+2) case. I did a 
function that requires one to write mixin(myDebug("1+2")); but 
that's not as good, especially because of the quoting that makes 
most IDE's unaware of the syntax inside (maybe monod would work 
but still...).

However there could be a clean D solution that alleviates need 
for macros:
I'd like to add __ARGS__ to the list of __FILE__, __LINE__, 
__FUNC___:

P1) 1st proposal:
__ARGS__ is a string representing the comma separated list of 
arguments passed:
void DEBUG(T,A)(T a, A args=__ARGS__){writeln(args,"=",a);}
void DEBUG2(T1,T2,A)(T1 a1,T2 a2, A args=__ARGS__){writeln(args);}
DEBUG(1+ 2); //will print "1+ 2=3", ie args="1+ 2"
DEBUG(1+ 2,
3*3);
//will print "1+ 2,3*3" (ie normalize the comma separation)

P2) same but __ARGS__ is string[] with one string per argument; 
the compiler already did the job of parsing, might as well use it:

void DEBUG(T)(T a1, T a2, string[] args=__ARGS__){
writeln(args[0],"=",a1);
writeln(args[1],"=",a2);
}

A question: whether or not to include the first argument in a 
UFCS/member function call ("hello".fun(1+2) ).

P3)
additionally, create a __CONTEXT__ that is a struct consisting of 
__ARGS__,__FILE__, __LINE__, __FUNC___. This has been proposed 
before and makes even more sense now. Additionally, it could give 
info on whether the call was UFCS'd or not, etc, information 
which is lost otherwise (I don't think traits could help 
distinguish which version was called, a.fun(b) or fun(a,b)).
Feb 01 2013
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-02-01 11:34, timotheecour wrote:
 One of the rare features I miss in C/C++ is stringification macro using
 "#x":

 ---
 #include ...
 #define DEBUG(x) disp_val(#x,x)
 template<typename T>
 void disp_val(const char*name, const T& x) {std::cout << name << "=" << x;}
 int main(){
 DEBUG(1+2); //will print 1+2=3 (and we can add line, file and func info)
 ASSERT(1+2==4); //can also be defined such that it'll print 1+2==4
 failed...
 }
 ---

 In D, we have built-in assert message that'll print the failing
 expression "1+2==4 failed" in case of failure but that's about it: no
 further processing can be done on that message, and there's nothing we
 can do about the DEBUG(1+2) case. I did a function that requires one to
 write mixin(myDebug("1+2")); but that's not as good, especially because
 of the quoting that makes most IDE's unaware of the syntax inside (maybe
 monod would work but still...).

 However there could be a clean D solution that alleviates need for macros:
 I'd like to add __ARGS__ to the list of __FILE__, __LINE__, __FUNC___:

 P1) 1st proposal:
 __ARGS__ is a string representing the comma separated list of arguments
 passed:
 void DEBUG(T,A)(T a, A args=__ARGS__){writeln(args,"=",a);}
 void DEBUG2(T1,T2,A)(T1 a1,T2 a2, A args=__ARGS__){writeln(args);}
 DEBUG(1+ 2); //will print "1+ 2=3", ie args="1+ 2"
 DEBUG(1+ 2,
 3*3);
 //will print "1+ 2,3*3" (ie normalize the comma separation)

 P2) same but __ARGS__ is string[] with one string per argument; the
 compiler already did the job of parsing, might as well use it:

 void DEBUG(T)(T a1, T a2, string[] args=__ARGS__){
 writeln(args[0],"=",a1);
 writeln(args[1],"=",a2);
 }

 A question: whether or not to include the first argument in a
 UFCS/member function call ("hello".fun(1+2) ).

 P3)
 additionally, create a __CONTEXT__ that is a struct consisting of
 __ARGS__,__FILE__, __LINE__, __FUNC___. This has been proposed before
 and makes even more sense now. Additionally, it could give info on
 whether the call was UFCS'd or not, etc, information which is lost
 otherwise (I don't think traits could help distinguish which version was
 called, a.fun(b) or fun(a,b)).

Sounds like an ugly hack for AST macros. This is a proposal for AST macros I've been working on. It's not finished but here it is: https://dl.dropbox.com/u/18386187/ast_macros.html -- /Jacob Carlborg
Feb 01 2013
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/01/2013 11:54 AM, Jacob Carlborg wrote:
 ...

 Sounds like an ugly hack for AST macros. This is a proposal for AST
 macros I've been working on. It's not finished but here it is:

 https://dl.dropbox.com/u/18386187/ast_macros.html

Make sure to include some way to pattern match on the syntax trees. (Otherwise we are back to manual parsing of the ast.toString() output.)
Feb 01 2013
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-02-01 12:24, Timon Gehr wrote:

 Make sure to include some way to pattern match on the syntax trees.
 (Otherwise we are back to manual parsing of the ast.toString() output.)

Why would pattern matching be needed? -- /Jacob Carlborg
Feb 01 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/01/2013 02:03 PM, Jacob Carlborg wrote:
 On 2013-02-01 12:24, Timon Gehr wrote:

 Make sure to include some way to pattern match on the syntax trees.
 (Otherwise we are back to manual parsing of the ast.toString() output.)

Why would pattern matching be needed?

Analysis and rewriting.
Feb 01 2013
parent reply Jacob Carlborg <doob me.com> writes:
On 2013-02-01 16:36, Timon Gehr wrote:

 Analysis and rewriting.

I'm just thinking an API similar to a reflection API. Something like: Ast!(Class) c; foreach (Ast!(Member) m ; c.members) { // do something with each member } Sure it would be easier and better looking with pattern matching. -- /Jacob Carlborg
Feb 01 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/01/2013 04:54 PM, Jacob Carlborg wrote:
 On 2013-02-01 16:36, Timon Gehr wrote:

 Analysis and rewriting.

I'm just thinking an API similar to a reflection API. Something like: Ast!(Class) c; foreach (Ast!(Member) m ; c.members) { // do something with each member }

Yes, that will work, as long as all necessary information is exposed.
 Sure it would be easier and better looking with pattern matching.

I take it you mean syntax sugar for pattern matching? AST macros have failed if they do not allow a decent library implementation of such functionality. :)
Feb 01 2013
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-02-01 18:53, bearophile wrote:

 That document about D macros could use a good list of possible usages
 (copying something from the Scala site is OK).

Yeah, more usage examples are always good. -- /Jacob Carlborg
Feb 01 2013
parent reply Jacob Carlborg <doob me.com> writes:
On 2013-02-02 00:58, bearophile wrote:
 The reflection they have added to Scala is sometimes used inside Scala
 macros:

 http://lampwww.epfl.ch/~michelou/scala/scala-reflection.html

"Sometimes", it's rather _required_ to basically do anything useful. -- /Jacob Carlborg
Feb 02 2013
parent Jacob Carlborg <doob me.com> writes:
On 2013-02-03 03:36, timotheecour wrote:
 seems like my original post regarding __ARGS__ was completely hijacked
 by the discussion on AST macros (however fruitful and interesting). I
 agree macros would solve this issue while providing a much more general
 solution, however, it's very unclear when that would be implemented,
 surely not anytime soon.

 Is there any other feedback on introducing __ARGS__  (see first post)
 besides AST macros being better? It's much simpler implementation-wise.

Sorry about that. I don't think that __ARGS__ is a bad idea, I just think that there are several features in D which could be replaced with a library solution using AST macros (if those were available). -- /Jacob Carlborg
Feb 03 2013
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-02-01 18:53, bearophile wrote:

 Maybe Jacob Carlborg is able to show what kind of syntax for pattern
 matching the macros are able to create (no need to actually implement it
 now).

How would a pattern matching feature look like and behave?. I can see if that would be possible to implement using the AST macros I'm thinking about. -- /Jacob Carlborg
Feb 04 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/04/2013 01:41 PM, Jacob Carlborg wrote:
 On 2013-02-01 18:53, bearophile wrote:

 Maybe Jacob Carlborg is able to show what kind of syntax for pattern
 matching the macros are able to create (no need to actually implement it
 now).

How would a pattern matching feature look like and behave?. I can see if that would be possible to implement using the AST macros I'm thinking about.

Well, ideally something like ast.match{ 2*(?a) => a+a, (?a)+2 => 2+a, (?e) => e, } The following would be feasible today, hacking around the usual hygiene issues: mixin(match!("ast",q{ 2*(?a) => a+a, (?a)+2 => 2+a, (?e) => e, });
Feb 04 2013
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-02-05 01:29, Timon Gehr wrote:

 Well, ideally something like

 ast.match{
      2*(?a)  => a+a,
      (?a)+2  => 2+a,
      (?e)    => e,
 }

Could you please elaborate how that would be, what the semantics would be. It doesn't look like any pattern matching I've seen in any other languages. For example, which value does it match on? -- /Jacob Carlborg
Feb 04 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/05/2013 08:26 AM, Jacob Carlborg wrote:
 On 2013-02-05 01:29, Timon Gehr wrote:

 Well, ideally something like

 ast.match{
      2*(?a)  => a+a,
      (?a)+2  => 2+a,
      (?e)    => e,
 }

Could you please elaborate how that would be, what the semantics would be. It doesn't look like any pattern matching I've seen in any other languages. For example, which value does it match on?

Eg: if ast == <[2*x]>, then the result will be <[x+x]> if ast == <[y+2]>, then the result will be <[2+y]>
Feb 05 2013
parent reply Jacob Carlborg <doob me.com> writes:
On 2013-02-05 12:12, Timon Gehr wrote:

 Eg:

 if ast == <[2*x]>, then the result will be <[x+x]>
 if ast == <[y+2]>, then the result will be <[2+y]>

How does the matching syntax work, like regular expression? -- /Jacob Carlborg
Feb 05 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/06/2013 08:57 AM, Jacob Carlborg wrote:
 On 2013-02-05 12:12, Timon Gehr wrote:

 Eg:

 if ast == <[2*x]>, then the result will be <[x+x]>
 if ast == <[y+2]>, then the result will be <[2+y]>

How does the matching syntax work, like regular expression?

Just like pattern matching usually works. '?a' identifiers are matched to subterms. (This is necessary because 'a' will match a symbol.)
Feb 06 2013
next sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-02-06 13:56, Timon Gehr wrote:

 Just like pattern matching usually works. '?a' identifiers are matched
 to subterms. (This is necessary because 'a' will match a symbol.)

I don't know how pattern matching usually works that's why I'm asking. But that syntax doesn't look like the ones I've seen, like in Scala. -- /Jacob Carlborg
Feb 06 2013
prev sibling parent dennis luehring <dl.soluz gmx.net> writes:
Am 06.02.2013 13:56, schrieb Timon Gehr:
 On 02/06/2013 08:57 AM, Jacob Carlborg wrote:
 On 2013-02-05 12:12, Timon Gehr wrote:

 Eg:

 if ast == <[2*x]>, then the result will be <[x+x]>
 if ast == <[y+2]>, then the result will be <[2+y]>

How does the matching syntax work, like regular expression?

Just like pattern matching usually works. '?a' identifiers are matched to subterms. (This is necessary because 'a' will match a symbol.)

i think regex (which are by design not nested-able) aren't enough for AST handling - because there is much nesting in ASTs
Feb 06 2013
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-02-05 01:29, Timon Gehr wrote:

 Well, ideally something like

 ast.match{
      2*(?a)  => a+a,
      (?a)+2  => 2+a,
      (?e)    => e,
 }

When I think about it, it can't look like that. What's passed to a macro needs to be syntactically valid. -- /Jacob Carlborg
Feb 05 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/05/2013 03:14 PM, Jacob Carlborg wrote:
 On 2013-02-05 01:29, Timon Gehr wrote:

 Well, ideally something like

 ast.match{
      2*(?a)  => a+a,
      (?a)+2  => 2+a,
      (?e)    => e,
 }

When I think about it, it can't look like that. What's passed to a macro needs to be syntactically valid.

I'd prefer if it needn't be. macro match(Context context, Ast ast, string code){ ... if(...) context.error("invalid syntax", code[a..b]); // (slice of code describes exact location where error // is shown to user at the call site.) ... }
Feb 05 2013
parent reply Jacob Carlborg <doob me.com> writes:
On 2013-02-05 16:24, Timon Gehr wrote:

 I'd prefer if it needn't be.

 macro match(Context context, Ast ast, string code){
      ...
      if(...) context.error("invalid syntax", code[a..b]);
      // (slice of code describes exact location where error
      // is shown to user at the call site.)
      ...
 }

The whole point of AST macros is that the compiler will do the lexing and parsing of the code. It will then just return an AST and it's up to the developer of the macro to implement the semantics. If the code is just passed as a string to the macro you would then need to lex and parse in addition to implementing the semantics and we would be no better than the current situation with string mixins. -- /Jacob Carlborg
Feb 05 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/05/2013 06:08 PM, Jacob Carlborg wrote:
 On 2013-02-05 16:24, Timon Gehr wrote:

 I'd prefer if it needn't be.

 macro match(Context context, Ast ast, string code){
      ...
      if(...) context.error("invalid syntax", code[a..b]);
      // (slice of code describes exact location where error
      // is shown to user at the call site.)
      ...
 }

The whole point of AST macros is that the compiler will do the lexing and parsing of the code. It will then just return an AST and it's up to the developer of the macro to implement the semantics.

If it's just about lexing and parsing, you need a lexer and a parser, not a macro.
 If the code is just passed as a string to the macro

That's just one option. Not all macros need to add syntax.
 you would then need to lex and parse in addition to implementing the semantics

If one chooses to do so. Parser generators can be provided.
 and we would be no better than the current situation with string mixins.

We surely would be better.
Feb 05 2013
parent Jacob Carlborg <doob me.com> writes:
On 2013-02-05 18:49, Timon Gehr wrote:

 If it's just about lexing and parsing, you need a lexer and a parser,
 not a macro.

Yeah, plus some syntax sugar.
 That's just one option. Not all macros need to add syntax.

True.
 If one chooses to do so. Parser generators can be provided.

Yes.
 and we would be no better than the current situation with string mixins.

We surely would be better.

-- /Jacob Carlborg
Feb 05 2013
prev sibling parent reply dennis luehring <dl.soluz gmx.net> writes:
Am 01.02.2013 12:24, schrieb Timon Gehr:
 On 02/01/2013 11:54 AM, Jacob Carlborg wrote:
 ...

 Sounds like an ugly hack for AST macros. This is a proposal for AST
 macros I've been working on. It's not finished but here it is:

 https://dl.dropbox.com/u/18386187/ast_macros.html

Make sure to include some way to pattern match on the syntax trees. (Otherwise we are back to manual parsing of the ast.toString() output.)

from the text "...The first parameter of macro is always of the type Context..." is then there a real need for context as an parameter - it semanticly similar to "this" in the class scope - i would prefer a "context" keyword inside of the macro scope
Feb 02 2013
next sibling parent reply dennis luehring <dl.soluz gmx.net> writes:
Am 03.02.2013 08:15, schrieb dennis luehring:
 Am 01.02.2013 12:24, schrieb Timon Gehr:
 On 02/01/2013 11:54 AM, Jacob Carlborg wrote:
 ...

 Sounds like an ugly hack for AST macros. This is a proposal for AST
 macros I've been working on. It's not finished but here it is:

 https://dl.dropbox.com/u/18386187/ast_macros.html

Make sure to include some way to pattern match on the syntax trees. (Otherwise we are back to manual parsing of the ast.toString() output.)

from the text "...The first parameter of macro is always of the type Context..." is then there a real need for context as an parameter - it semanticly similar to "this" in the class scope - i would prefer a "context" keyword inside of the macro scope

i understand that pushing the context und sub-macro is a need but didn't you define a macro-type by alias macro (Ast!(string) str) my_macro and this type can be used by sub-macros like normal typed parameters another question: why Ast! here - can the input any else than a AST? and why not use your $ notation not also here $string?
Feb 03 2013
parent Jacob Carlborg <doob me.com> writes:
On 2013-02-03 09:44, dennis luehring wrote:

 i understand that pushing the context und sub-macro is a need

 but didn't you define a macro-type by

 alias macro (Ast!(string) str) my_macro

 and this type can be used by sub-macros like normal typed parameters

I'm not sure I understand the above.
 another question:

 why Ast! here - can the input any else than a AST?
 and why not use your $ notation not also here $string?

Ast would be a type defined, most likely, by druntime. I'm trying to minimize the syntactic changes needed to implement this feature request. It's not even sure that the $val syntax would be used. Take a look at the "ast" macro. -- /Jacob Carlborg
Feb 03 2013
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-02-03 08:15, dennis luehring wrote:

 from the text

 "...The first parameter of macro is always of the type Context..."

 is then there a real need for context as an parameter - it semanticly
 similar to "this" in the class scope - i would prefer a "context"
 keyword inside of the macro scope

One reason is to not have to introduce a new keyword, which in general is not very popular around here. Note that "macro" keyword is already reserved for future use, just for a feature like this. -- /Jacob Carlborg
Feb 03 2013
prev sibling next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-02-01 15:35, bearophile wrote:

 Maybe it's the first serious proposal for D macros I see :-)

 Is it possible to re-use the <[ ]> syntax (and $...) for other purposes?

That syntax is just an abstract syntax, it does not need to look like that. I'm thinking we could do something similar to Scala's reify macro. I call this the "ast" macro. Look at the header "The AST Macro". But to answer your question, no. It didn't cross my mind.
 Have you seen the macros of Scala language? http://scalamacros.org/

Yes, this proposal is basically the same as macros in Scala, just adapted the syntax for D.
 Regarding the attribute macros, my main use case for them is to extend
 the D type system in some ways. How well is such usage supported?

It might be possible, depending on what you want/need. I'm thinking you can do something like this: foo int a; Which is replaced with: Foo!(int) a; It's a different type so depending on how you look at it you could say it affected the type system. -- /Jacob Carlborg
Feb 01 2013
parent Jacob Carlborg <doob me.com> writes:
On 2013-02-01 16:55, bearophile wrote:
 Jacob Carlborg:

 But to answer your question, no. It didn't cross my mind.

OK. (I have asked because syntax costs, so it's good to use it as much as possible, if it doesn't lead to ambiguities).

Yes, that's why I was thinking if we could do like Scala and implement it as in library, as a macro.
 I meant something more like (the now closed) Treehydra:
 https://developer.mozilla.org/en-US/docs/Treehydra_Manual

Could you give a quick, simple and small example of how you would like it to work in pseudo code or D? -- /Jacob Carlborg
Feb 01 2013
prev sibling next sibling parent reply Dejan Lekic <dejan.lekic gmail.com> writes:
Jacob Carlborg wrote:

 On 2013-02-01 11:34, timotheecour wrote:
 One of the rare features I miss in C/C++ is stringification macro using
 "#x":

 ---
 #include ...
 #define DEBUG(x) disp_val(#x,x)
 template<typename T>
 void disp_val(const char*name, const T& x) {std::cout << name << "=" << x;}
 int main(){
 DEBUG(1+2); //will print 1+2=3 (and we can add line, file and func info)
 ASSERT(1+2==4); //can also be defined such that it'll print 1+2==4
 failed...
 }
 ---

 In D, we have built-in assert message that'll print the failing
 expression "1+2==4 failed" in case of failure but that's about it: no
 further processing can be done on that message, and there's nothing we
 can do about the DEBUG(1+2) case. I did a function that requires one to
 write mixin(myDebug("1+2")); but that's not as good, especially because
 of the quoting that makes most IDE's unaware of the syntax inside (maybe
 monod would work but still...).

 However there could be a clean D solution that alleviates need for macros:
 I'd like to add __ARGS__ to the list of __FILE__, __LINE__, __FUNC___:

 P1) 1st proposal:
 __ARGS__ is a string representing the comma separated list of arguments
 passed:
 void DEBUG(T,A)(T a, A args=__ARGS__){writeln(args,"=",a);}
 void DEBUG2(T1,T2,A)(T1 a1,T2 a2, A args=__ARGS__){writeln(args);}
 DEBUG(1+ 2); //will print "1+ 2=3", ie args="1+ 2"
 DEBUG(1+ 2,
 3*3);
 //will print "1+ 2,3*3" (ie normalize the comma separation)

 P2) same but __ARGS__ is string[] with one string per argument; the
 compiler already did the job of parsing, might as well use it:

 void DEBUG(T)(T a1, T a2, string[] args=__ARGS__){
 writeln(args[0],"=",a1);
 writeln(args[1],"=",a2);
 }

 A question: whether or not to include the first argument in a
 UFCS/member function call ("hello".fun(1+2) ).

 P3)
 additionally, create a __CONTEXT__ that is a struct consisting of
 __ARGS__,__FILE__, __LINE__, __FUNC___. This has been proposed before
 and makes even more sense now. Additionally, it could give info on
 whether the call was UFCS'd or not, etc, information which is lost
 otherwise (I don't think traits could help distinguish which version was
 called, a.fun(b) or fun(a,b)).

Sounds like an ugly hack for AST macros. This is a proposal for AST macros I've been working on. It's not finished but here it is: https://dl.dropbox.com/u/18386187/ast_macros.html

+1 Jacob, I humbly believe this should be a new DIP ... This proposal, if realised, would bring very useful feature to D... -- Dejan Lekic dejan.lekic (a) gmail.com http://dejan.lekic.org
Feb 03 2013
parent reply Jacob Carlborg <doob me.com> writes:
On 2013-02-03 21:25, Dejan Lekic wrote:

 +1

 Jacob, I humbly believe this should be a new DIP ... This proposal, if
realised,
 would bring very useful feature to D...

I'm not really sure what to do about hygienicy. -- /Jacob Carlborg
Feb 04 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/04/2013 01:36 PM, Jacob Carlborg wrote:
 On 2013-02-03 21:25, Dejan Lekic wrote:

 +1

 Jacob, I humbly believe this should be a new DIP ... This proposal, if
 realised,
 would bring very useful feature to D...

I'm not really sure what to do about hygienicy.

IMO macros should be fully hygienic by default, with opt-out options.
Feb 04 2013
parent reply Jacob Carlborg <doob me.com> writes:
On 2013-02-05 01:15, Timon Gehr wrote:

 IMO macros should be fully hygienic by default, with opt-out options.

That's the opposite of how the macros in Scala works. It's quite easy to say if it should be hygienic or not. The hard part is to figure out the details and how to break hygienicy, when there's need for it. -- /Jacob Carlborg
Feb 04 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/05/2013 08:28 AM, Jacob Carlborg wrote:
 On 2013-02-05 01:15, Timon Gehr wrote:

 IMO macros should be fully hygienic by default, with opt-out options.

That's the opposite of how the macros in Scala works.

As far as my understanding goes, quasi-quoting is hygienic, and manual AST building provides both options.
 It's quite easy to say if it should be hygienic or not. The hard part is
 to figure out the details and how to break hygienicy, when there's need
 for it.

We could provide all nested scopes in an array as part of the context. macro foo(Context context){ return<[ context.scopes[0].x++; context.scopes[1].x++; ]>; } int x = 2; void main(){ int x=0; foo(); assert(x==1 && .x==3); } If manual AST building is supported, it could additionally do something along the following lines: module macros; int x=0; macro foo(Context context){ return SequenceExp( AssignExp(Symbol!x(), Constant(1)), AssignExp(Identifier("x"), Constant(2)), ); } // --- module m; import macros; int x=0; void main(){ foo(); assert(macros.x==1 && x==2); }
Feb 05 2013
parent reply Jacob Carlborg <doob me.com> writes:
On 2013-02-05 12:05, Timon Gehr wrote:

 As far as my understanding goes, quasi-quoting is hygienic, and manual
 AST building provides both options.

Yes, that's usually how it works.
 We could provide all nested scopes in an array as part of the context.

 macro foo(Context context){
      return<[
          context.scopes[0].x++;
          context.scopes[1].x++;
      ]>;
 }
 int x = 2;
 void main(){
      int x=0;
      foo();
      assert(x==1 && .x==3);
 }

How would one navigate these scopes. How would one know which one to use? If I recall correctly Nemerle has a way to indicate a symbol should refer to a symbol at the call site which has the closest lexical scope. We would need a way to introduce a new symbol which does not leak outside the macro and another way to explicitly say the symbol is available outside the macro at call site. So if I do something like: int x; macro foo (Context context) { int y; return <[ x++; y++; ]>; } The above would increment "x" and "y" available in the macro context and not refer to any symbols at the call site? -- /Jacob Carlborg
Feb 05 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/06/2013 08:48 AM, Jacob Carlborg wrote:
 On 2013-02-05 12:05, Timon Gehr wrote:

 As far as my understanding goes, quasi-quoting is hygienic, and manual
 AST building provides both options.

Yes, that's usually how it works.
 We could provide all nested scopes in an array as part of the context.

 macro foo(Context context){
      return<[
          context.scopes[0].x++;
          context.scopes[1].x++;
      ]>;
 }
 int x = 2;
 void main(){
      int x=0;
      foo();
      assert(x==1 && .x==3);
 }

How would one navigate these scopes. How would one know which one to use? If I recall correctly Nemerle has a way to indicate a symbol should refer to a symbol at the call site which has the closest lexical scope.

That would be looking it up in scopes[0]. (Nested scopes continue symbol lookup in the parent scopes.) The most important cases are scopes[0] and scopes[$-1], the caller scope and the module scope.
 We would need a way to introduce a new symbol which does not leak
 outside the macro and another way to explicitly say the symbol is
 available outside the macro at call site.

 So if I do something like:

 int x;

 macro foo (Context context)
 {
      int y;
      return <[
          x++;
          y++;
      ]>;
 }

 The above would increment "x" and "y" available in the macro context and
 not refer to any symbols at the call site?

Yes, but it is not clear yet what macro closures are exactly (Probably it would make sense to inject the closed over declarations at the call site, without adding them to the scope.)
Feb 06 2013
parent reply Jacob Carlborg <doob me.com> writes:
On 2013-02-06 14:05, Timon Gehr wrote:

 Yes, but it is not clear yet what macro closures are exactly (Probably
 it would make sense to inject the closed over declarations at the call
 site, without adding them to the scope.)

It's not clear? We want to be able have a macro referring to utility functions and these should be bind at the macro site and not call site. -- /Jacob Carlborg
Feb 06 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 02/06/2013 03:23 PM, Jacob Carlborg wrote:
 On 2013-02-06 14:05, Timon Gehr wrote:

 Yes, but it is not clear yet what macro closures are exactly (Probably
 it would make sense to inject the closed over declarations at the call
 site, without adding them to the scope.)

It's not clear? We want to be able have a macro referring to utility functions and these should be bind at the macro site and not call site.

Of course. What I mean by macro closure is the following: Ast foo(){ int x = 0; // a 'closed over' variable return <[x]>; // escaping reference } macro counter(){ return $(foo())++; }
Feb 06 2013
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 02/06/2013 03:57 PM, Timon Gehr wrote:
 On 02/06/2013 03:23 PM, Jacob Carlborg wrote:
 On 2013-02-06 14:05, Timon Gehr wrote:

 Yes, but it is not clear yet what macro closures are exactly (Probably
 it would make sense to inject the closed over declarations at the call
 site, without adding them to the scope.)

It's not clear? We want to be able have a macro referring to utility functions and these should be bind at the macro site and not call site.

Of course. What I mean by macro closure is the following: Ast foo(){ int x = 0; // a 'closed over' variable return <[x]>; // escaping reference } macro counter(){ return $(foo())++; }

Actually macro counter(){ return <[$(foo())++]>; }
Feb 06 2013
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-02-06 15:57, Timon Gehr wrote:

 Of course. What I mean by macro closure is the following:

 Ast foo(){
      int x = 0;    // a 'closed over' variable
      return <[x]>; // escaping reference
 }

 macro counter(){ return $(foo())++; }

Aha, you mean like that, I see. -- /Jacob Carlborg
Feb 06 2013
prev sibling parent Dejan Lekic <dejan.lekic gmail.com> writes:
Jacob Carlborg wrote:

 On 2013-02-01 11:34, timotheecour wrote:
 One of the rare features I miss in C/C++ is stringification macro using
 "#x":

 ---
 #include ...
 #define DEBUG(x) disp_val(#x,x)
 template<typename T>
 void disp_val(const char*name, const T& x) {std::cout << name << "=" << x;}
 int main(){
 DEBUG(1+2); //will print 1+2=3 (and we can add line, file and func info)
 ASSERT(1+2==4); //can also be defined such that it'll print 1+2==4
 failed...
 }
 ---

 In D, we have built-in assert message that'll print the failing
 expression "1+2==4 failed" in case of failure but that's about it: no
 further processing can be done on that message, and there's nothing we
 can do about the DEBUG(1+2) case. I did a function that requires one to
 write mixin(myDebug("1+2")); but that's not as good, especially because
 of the quoting that makes most IDE's unaware of the syntax inside (maybe
 monod would work but still...).

 However there could be a clean D solution that alleviates need for macros:
 I'd like to add __ARGS__ to the list of __FILE__, __LINE__, __FUNC___:

 P1) 1st proposal:
 __ARGS__ is a string representing the comma separated list of arguments
 passed:
 void DEBUG(T,A)(T a, A args=__ARGS__){writeln(args,"=",a);}
 void DEBUG2(T1,T2,A)(T1 a1,T2 a2, A args=__ARGS__){writeln(args);}
 DEBUG(1+ 2); //will print "1+ 2=3", ie args="1+ 2"
 DEBUG(1+ 2,
 3*3);
 //will print "1+ 2,3*3" (ie normalize the comma separation)

 P2) same but __ARGS__ is string[] with one string per argument; the
 compiler already did the job of parsing, might as well use it:

 void DEBUG(T)(T a1, T a2, string[] args=__ARGS__){
 writeln(args[0],"=",a1);
 writeln(args[1],"=",a2);
 }

 A question: whether or not to include the first argument in a
 UFCS/member function call ("hello".fun(1+2) ).

 P3)
 additionally, create a __CONTEXT__ that is a struct consisting of
 __ARGS__,__FILE__, __LINE__, __FUNC___. This has been proposed before
 and makes even more sense now. Additionally, it could give info on
 whether the call was UFCS'd or not, etc, information which is lost
 otherwise (I don't think traits could help distinguish which version was
 called, a.fun(b) or fun(a,b)).

Sounds like an ugly hack for AST macros. This is a proposal for AST macros I've been working on. It's not finished but here it is: https://dl.dropbox.com/u/18386187/ast_macros.html

+1 Jacob, I humbly believe this should be a new DIP ... This proposal, if realised, would bring very useful feature to D... -- Dejan Lekic dejan.lekic (a) gmail.com http://dejan.lekic.org
Feb 03 2013
prev sibling next sibling parent "Dicebot" <m.strashun gmail.com> writes:
.stringof does pretty much the same, but, unfortunately, there is 
no way to pass an expression to template/function without 
evaluating it.
Feb 01 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Jacob Carlborg:

 This is a proposal for AST macros I've been working on.
 It's not finished but here it is:
 https://dl.dropbox.com/u/18386187/ast_macros.html

Maybe it's the first serious proposal for D macros I see :-) Is it possible to re-use the <[ ]> syntax (and $...) for other purposes? Have you seen the macros of Scala language? http://scalamacros.org/ Regarding the attribute macros, my main use case for them is to extend the D type system in some ways. How well is such usage supported? Bye, bearophile
Feb 01 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Jacob Carlborg:

 But to answer your question, no. It didn't cross my mind.

OK. (I have asked because syntax costs, so it's good to use it as much as possible, if it doesn't lead to ambiguities).
 Yes, this proposal is basically the same as macros in Scala, 
 just adapted the syntax for D.

I think Scala macros are simple to implement :-)
 It might be possible, depending on what you want/need. I'm 
 thinking you can do something like this:

  foo int a;

 Which is replaced with:

 Foo!(int) a;

 It's a different type so depending on how you look at it you 
 could say it affected the type system.

I meant something more like (the now closed) Treehydra: https://developer.mozilla.org/en-US/docs/Treehydra_Manual Bye, bearophile
Feb 01 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Timon Gehr:

 I take it you mean syntax sugar for pattern matching? AST 
 macros have failed if they do not allow a decent library 
 implementation of such functionality. :)

Maybe Jacob Carlborg is able to show what kind of syntax for pattern matching the macros are able to create (no need to actually implement it now). That document about D macros could use a good list of possible usages (copying something from the Scala site is OK). Bye, bearophile
Feb 01 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
The reflection they have added to Scala is sometimes used inside 
Scala macros:

http://lampwww.epfl.ch/~michelou/scala/scala-reflection.html

Bye,
bearophile
Feb 01 2013
prev sibling next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
And then I suggest to put the incomplete proposal for the macros 
in Bugzilla o DWiki or even in a DEP.

Bye,
bearophile
Feb 02 2013
prev sibling next sibling parent "Jacob Carlborg" <doob me.com> writes:
On Saturday, 2 February 2013 at 11:12:18 UTC, bearophile wrote:
 And then I suggest to put the incomplete proposal for the 
 macros in Bugzilla o DWiki or even in a DEP.

I'm planning to do that. I was going to work on it a bit more but now when it's already out in the wild I'll create a DIP. BTW, it's called DIP, as in D Improvement Proposal, not DEP. http://wiki.dlang.org/DIPs -- /Jacob Carlborg
Feb 02 2013
prev sibling next sibling parent "timotheecour" <thelastmammoth gmail.com> writes:
seems like my original post regarding __ARGS__ was completely 
hijacked by the discussion on AST macros (however fruitful and 
interesting). I agree macros would solve this issue while 
providing a much more general solution, however, it's very 
unclear when that would be implemented, surely not anytime soon.

Is there any other feedback on introducing __ARGS__  (see first 
post) besides AST macros being better? It's much simpler 
implementation-wise.
Feb 02 2013
prev sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Dejan Lekic:

 Jacob, I humbly believe this should be a new DIP ...

I agree.
 This proposal, if realised, would bring very useful feature to 
 D...

The Scala-style macros, with enough reflection (plus maybe pattern matching implemented with the macro themselves) are able to expand the flexibility of D. But macros have some costs. They add complexity to the language, and make code that uses macros less easy to understand. The almost only good place to use macros is in well known and well debugged library code, standard code, like in Phobos. Most D programmers are not going to be able to use macros. If you add macros you create even more the levels of programmers they talk about in Scala: http://www.scala-lang.org/node/8610 One of the most powerful and useful features of CommonLisp (and similar languages) are macros. They add power to the language, but flexibility itself has a high cost. It makes hard for the programmer A to understand and use code written by programmer B. It goes against some of the things that foster the creation of an ecology of reusable modules as in Python and Perl. Too much flexibility is dangerous. Even Scala is risking that with its macros. Lot of programming situations where today Java is used aren't going to use Scala and its macros. Macros are both part of the power of Lisp and one of the causes of its "failure". So it's a matter of balancing things: are macros going to give to D more than the (high) price they ask for? I like AST macros, but I don't know the answer. Bye, bearophile
Feb 03 2013