Is it possible to handle 'magic' property assignments a'la PHP?

Jacob Carlborg doob at me.com
Thu Jan 9 00:49:17 PST 2014


On 2014-01-08 19:04, H. S. Teoh wrote:

> The reason I wrote it this way is so that it parallels the foreach
> construction better:
>
> 	my_foreach (i; range) {
> 		...
> 	}
>
> parallels:
>
> 	foreach (i; range) {
> 		...
> 	}

I guessed that.

> Keep in mind that the identifier list before the ';' is actually the
> delegate's parameter list, it's not passing anything in. They are
> placeholders for what the function will pass to the delegate. So:
>
> 	my_foreach (i,j ; range) {
> 		writeln(i + j);
> 	}
>
> actually means:
>
> 	my_foreach(range, (i,j) => writeln(i + j));

Yeah, I know.

> and my_foreach could be implemented something like this:
>
> 	void my_foreach(alias dg, R)(R range)
> 		if (is(typeof(dg(size_t.init, ElementType!R.init))))
> 	{
> 		size_t idx = 0;
> 		while (!range.empty) {
> 			// N.B.: calls dg with i = idx, j = range.front
> 			dg(idx, range.front);
>
> 			range.popFront();
> 			idx++;
> 		}
> 	}
>
>
> If we go by this, then UFCS should still work:
>
> 	range.my_foreach(i,j) { /* body */ }
>
> should be translated to:
>
> 	my_foreach(i, j ; range) { /* body */ }
>
> which in turn translates to:
>
> 	my_foreach!((i, j) { /* body */ })(range);
>
> In the first case, there is no ambiguity with `range.my_foreach(i,j);`,
> which should translate to `my_foreach(range,i,j);`, because the presence
> of the trailing code block without an intervening ';' makes it clear
> that the above is intended, rather than `my_foreach(range,i,j);`.

Didn't think of that.

> In fact, we can already almost get the desired syntax in the current
> language:
>
> 	/* Current D already supports this: */
> 	range.my_foreach!((i,j) {
> 		/* body */
> 	});

Almost ;)

> which isn't that much different from the proposed syntactic sugar:
>
> 	range.my_foreach(i,j) {
> 		/* body */
> 	}
>
> We're just saving on the '!', ';', and an extra pair of parentheses.

It quickly get clumsy when you need to pass regular arguments to the 
function:

void foo (alias dg) (int a, int b);

foo!((i, j) {
     // body
})(1, 2);

Not pretty.

> I guess the only real advantage is that we get to imitate built-in
> foreach syntax. E.g., if we use the form with arguments but no indexing
> arguments, we can pretend to be an if-statement:
>
> 	// (Whatever "dynamic if" means...)
> 	void dynamic_if(alias dg)(bool cond)
> 		if (is(typeof(dg())))
> 	{
> 		// Haha, we're just wrapping the built-in 'if' cuz we
> 		// can.
> 		if (cond) dg();
> 	}
>
> 	int x;
> 	dynamic_if (x==0) {
> 		writeln("Boo yah!");
> 	}
>
> Or if we use the argumentless form to implement custom block constructs:

BTW, what do you think about not needing braces if the delegate body 
only contains a single statement, like with regular statements:

dynamic_if (x==0)
     writeln("foo");

With the alias syntax, I'm wondering if the compiler will have any 
problem with that you can pass almost anything to an alias parameter and 
not just a delegate.

-- 
/Jacob Carlborg


More information about the Digitalmars-d-learn mailing list