March 07, 2019
On Wednesday, 6 March 2019 at 18:06:34 UTC, Basile B. wrote:

>   The "Postfix type notation", to quote your naming of it, can be ambiguous and it breaks the C-ish looking style of D. Example of ambiguity:
>
> [...]

Hmm, thanks for pointing that out! I guess that's indeed ambiguous without parens or something.

>
> [...]

Yeah I guess I can do that as well as another option.
March 07, 2019
On Thursday, 7 March 2019 at 19:43:31 UTC, aliak wrote:
> Thanks for that code above!
>
> And hmm.. __GENSYM__ ... is this documented anywhere? (I found a post by you on the forum about it but nothing in the docs)

`gensym` is a function in some Lisp-family languages that's used to generate unique ientifiers for use in macros. [1] It sounds like __GENSYM__ is a proposed version of this for D, implemented as a compiler builtin like __FILE__ and __LINE__.

[1] http://clhs.lisp.se/Body/f_gensym.htm
March 07, 2019
On Thu, Mar 07, 2019 at 08:22:36PM +0000, Paul Backus via Digitalmars-d wrote:
> On Thursday, 7 March 2019 at 19:43:31 UTC, aliak wrote:
> > Thanks for that code above!
> > 
> > And hmm.. __GENSYM__ ... is this documented anywhere? (I found a post by you on the forum about it but nothing in the docs)
> 
> `gensym` is a function in some Lisp-family languages that's used to generate unique ientifiers for use in macros. [1] It sounds like __GENSYM__ is a proposed version of this for D, implemented as a compiler builtin like __FILE__ and __LINE__.
> 
> [1] http://clhs.lisp.se/Body/f_gensym.htm

I've found the need for generating unique identifiers before, especially for temporaries inside `static foreach`.  One day, it dawned on me that templates can be be used to generate new names, precisely because each template instantiation is given a unique identifier based on the template arguments:

	struct S(size_t i) {
		... // declarations that depend on i
	}

	static foreach (i; 0 .. 10) {{
		S!i x; // <-- bingo, new type identifier per loop index!
	}}

Unfortunately, this does not solve the problem of unique identifiers for the variable name (as opposed to the type name). But perhaps the same idea of using templates to generate identifiers might still be applicable:

	// Warning: untested concept code
	alias gensym(size_t line = __LINE__) = Option!(int, "", "", "", 0);

Or something along these lines, might be the ticket?  Essentially, generate a new identifier keyed on __LINE__ (you could also add __FILE__ if you wish to differentiate between declarations across source files). So the identifiers would be gensym!123, gensym!456, etc..


T

-- 
What are you when you run out of Monet? Baroque.
March 08, 2019
On Thursday, 7 March 2019 at 20:18:28 UTC, aliak wrote:
> Hmm, thanks for pointing that out! I guess that's indeed ambiguous without parens or something.

I'm not in favor of adding a second type syntax, but note that the current scheme is also ambiguous:

const int[]

Is that const(int[]) or const(int)[]? It's the former, if you want the latter use explicit parentheses. Operators in general are full of ambiguities that are solved by precedence and associativity rules and parens to override them.
March 09, 2019
On Thursday, 7 March 2019 at 21:06:28 UTC, H. S. Teoh wrote:
> Unfortunately, this does not solve the problem of unique identifiers for the variable name (as opposed to the type name). But perhaps the same idea of using templates to generate identifiers might still be applicable:
>
> 	// Warning: untested concept code
> 	alias gensym(size_t line = __LINE__) = Option!(int, "", "", "", 0);
>
> Or something along these lines, might be the ticket?  Essentially, generate a new identifier keyed on __LINE__ (you could also add __FILE__ if you wish to differentiate between declarations across source files). So the identifiers would be gensym!123, gensym!456, etc..
>
>
> T

The only issue with using __LINE__ is that it requires gensym to be evaluated in the same scope as the one the variable is being declared in. For example, if you have a function that generates code as a string for use as a mixin, you can't use a __LINE__-based gensym to name symbols in the generated code:

import std.format;

string gensym(size_t id = __LINE__) {
    return format("_gensym_%d", id);
}

string generateCode() {
    enum varName = gensym;
    return q{
        import std.stdio;
        int %1$s = 123;
        writeln("%1$s = ", %1$s);
    }.format(varName);
}

void main() {
    mixin(generateCode);
    //mixin(generateCode); // Error: _gensym_8 is already defined
}

In Lisp, gensym uses a global counter (like GCC's __COUNTER__ macro [1]), so this isn't an issue.

[1] https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
March 11, 2019
On Saturday, 9 March 2019 at 20:50:37 UTC, Paul Backus wrote:

> The only issue with using __LINE__ is that it requires gensym to be evaluated in the same scope as the one the variable is being declared in.

There are other issues:

string gensym(size_t id = __LINE__) {
    return format("_gensym_%d", id);
}

static assert(gensym() == gensym()); // We don't want this to pass.

unittest {
    string[2] s;
    static foreach (i; 0..2) {
        s[i] = gensym;
    }
    assert(s[0] == s[1]); // Nor this.
}

The first would be fixed by having __COL__ (being the column of the line on which gensym is being called). However, that does nothing for the second case.

--
  Simen
March 11, 2019
On Monday, 11 March 2019 at 08:13:04 UTC, Simen Kjærås wrote:
> On Saturday, 9 March 2019 at 20:50:37 UTC, Paul Backus wrote:
>
>> The only issue with using __LINE__ is that it requires gensym to be evaluated in the same scope as the one the variable is being declared in.
>
> There are other issues:
>
> string gensym(size_t id = __LINE__) {
>     return format("_gensym_%d", id);
> }
>
> static assert(gensym() == gensym()); // We don't want this to pass.
>
> unittest {
>     string[2] s;
>     static foreach (i; 0..2) {
>         s[i] = gensym;
>     }
>     assert(s[0] == s[1]); // Nor this.
> }
>
> The first would be fixed by having __COL__ (being the column of the line on which gensym is being called). However, that does nothing for the second case.
>
> --
>   Simen

These are definitely annoying, but you can at least get around them by writing stuff like `gensym(i)`, as suggested in H. S. Teoh's post.
March 31, 2019
On Thursday, 7 March 2019 at 19:43:31 UTC, aliak wrote:
> On Wednesday, 6 March 2019 at 08:09:48 UTC, Simen Kjærås wrote:
>> On Wednesday, 6 March 2019 at 07:53:42 UTC, Simen Kjærås wrote:
>>> alias port = Option!(immutable ushort, "p|port", "Sets the port used for serving.", "PORT", 8888);
>>
>> Of course, one issue is the lack of __GENSYM__, meaning that this will only declare one variable, with two aliases:
>>
>> alias a = Option!(int, "", "", "", 0);
>> alias b = Option!(int, "", "", "", 0);
>>
>> unittest {
>>     assert(&a == &b);
>> }
>>
>> --
>>   Simen
>
> Thanks for that code above!
>
> And hmm.. __GENSYM__ ... is this documented anywhere? (I found a post by you on the forum about it but nothing in the docs)

Sorry guys, I did see the question about Kotlin when googling, but I re-asked it for not to get answers like "Because Kotlin (Go, Rust, ...) dev team decided like this". I was interested in a more common answer: why does it become kind of an epidemic?
1 2
Next ›   Last »