December 02, 2012
On Sunday, 2 December 2012 at 06:58:12 UTC, Jonathan M Davis wrote:
> On Sunday, December 02, 2012 07:49:52 deadalnix wrote:
>> And what do you think about map!(x => x * x) = generator(x, y, z)
>> ?
>
> What's that even supposed to mean? map has been given no function argument
> either as UFCS or with a normal function call, so it's not being called. And
> even if it were, it wouldn't result in an lvalue, so putting it on the left of
> an assignment makes no sense. I have no idea what you're trying to do here.
>

I want to express that regular function are really different than regular function calls. If map had to behave like a property, then the code above would be correct, and 100% equivalent to Andrei's snippet.
December 02, 2012
On 12/02/12 07:57, Jonathan M Davis wrote:
> On Sunday, December 02, 2012 07:49:52 deadalnix wrote:
>> And what do you think about map!(x => x * x) = generator(x, y, z)
>> ?
> 
> What's that even supposed to mean? map has been given no function argument either as UFCS or with a normal function call, so it's not being called. And even if it were, it wouldn't result in an lvalue, so putting it on the left of an assignment makes no sense. I have no idea what you're trying to do here.

   void main() {
      import std.stdio;

      writeln!string = "Hello World!";
   }

   // The explicit "!string" is only needed because of no IFTI, if 'writeln' was
   // a function instead of a template you could just call it like "writeln = "blah".

Allowing that /by default/ does much more harm than good, proper property enforcement is necessary. Function calls go via '()'. Programmer can override when he knows better. UFCS doesn't change things. [1]

artur

[1] If you think the required '()' in UFCS chains look ugly, you're right, but the
right fix isn't to butcher the language. '()' carry important information. Having
a mode where function calls are made w/o the parens would be a good idea, but it
should be limited to an explicit scope. ie something like
"auto r = function {generator(x, y, z).map!(x => x * x)};", except 'function' keyword
can't be overloaded like that, it's too long, and ()-less calls isn't the only change
that could be done.
December 02, 2012
On 12/2/12, deadalnix <deadalnix@gmail.com> wrote:
> BTW, I can't edit in the wiki? When I try to do so, it says me that deadalnix is an invalid username. If I need to register, I didn't found out how.

It requires a silly CamelCase style username. You can try and edit the new wiki though: http://dwiki.kimsufi.thecybershadow.net/Main_Page
December 02, 2012
On Sunday, December 02, 2012 12:36:53 Artur Skawina wrote:
> [1] If you think the required '()' in UFCS chains look ugly, you're right, but the right fix isn't to butcher the language.

I agree, but those who think that seem to be outnumbered by those who don't want to have to use the parens - particularly with functions which already require a template argument.

- Jonathan M Davis
December 02, 2012
There's more than just @property that operate like variables.

Should we restrict this as well?

struct stdio
{
   void opAssign(T)( T a_arg )
   {
      writeln( a_arg );
   }
}

main()
{
   stdio writeln;
   writeln = "hellow world";
}

Conceptually, I don't see why we have to impose a difference between how variables are assigned and how functions are called.

A variable "=" assignment is simply a special case of a function call that is written for you by the compiler.

The example of opAssign shows that for some time now, there's been pressure to eliminate the difference in at least some cases, and allow the programmer to implement their own version of the assignment function call.

If you want to remove inconsistencies, then the way functions and variables are manipulated should be unified.

If someone can honestly demonstrate a non-subjective reason why there must be a difference between function call and variable assignments, please show it. So far I've only seen arguments that boil down to "I don't like it".

--rt

December 02, 2012
There's more than just @property that operate like variables.

Should we restrict this as well?

struct stdio
{
    void opAssign(T)( T a_arg )
    {
       writeln( a_arg );
    }
}

main()
{
    stdio writeln;
    writeln = "hellow world";
}

Conceptually, I don't see why we have to impose a difference
between how variables are assigned and how functions are called.

A variable "=" assignment is simply a special case of a function
call that is written for you by the compiler.

The example of opAssign shows that for some time now, there's
been pressure to eliminate the difference in at least some cases,
and allow the programmer to implement their own version of the
assignment function call.

If you want to remove inconsistencies, then the way functions and
variables are manipulated should be unified.

If someone can honestly demonstrate a non-subjective reason why
there must be a difference between function call and variable
assignments, please show it. So far I've only seen arguments that
boil down to "I don't like it".

--rt

December 02, 2012
On Sun, 02 Dec 2012 18:47:26 -0000, Rob T <rob@ucora.com> wrote:
> If someone can honestly demonstrate a non-subjective reason why there must be a difference between function call and variable assignments, please show it. So far I've only seen arguments that boil down to "I don't like it".

A variable assignment is in 99% of cases a simple operation.  A function call is in 99% of cases a more complex operation.  Being able to immediately "see" those costs is useful.  A language which allows you to make variable assignments costly will be inherently harder to understand in terms of cost, than a language which does not.

R

-- 
Using Opera's revolutionary email client: http://www.opera.com/mail/
December 02, 2012
On 12/02/12 19:48, Rob T wrote:
> There's more than just @property that operate like variables.
> 
> Should we restrict this as well?
> 
> struct stdio
> {
>     void opAssign(T)( T a_arg )
>     {
>        writeln( a_arg );
>     }
> }
> 
> main()
> {
>     stdio writeln;
>     writeln = "hellow world";
> }
> 
> Conceptually, I don't see why we have to impose a difference between how variables are assigned and how functions are called.
> 
> A variable "=" assignment is simply a special case of a function call that is written for you by the compiler.
> 
> The example of opAssign shows that for some time now, there's been pressure to eliminate the difference in at least some cases, and allow the programmer to implement their own version of the assignment function call.
> 
> If you want to remove inconsistencies, then the way functions and variables are manipulated should be unified.
>
> If someone can honestly demonstrate a non-subjective reason why there must be a difference between function call and variable assignments, please show it. So far I've only seen arguments that boil down to "I don't like it".

Do you seriously think that there is no difference and would like to have to decypher code like

   void main() {
      import std.stdio, std.math;
      writeln(sqrt=81);
   }

?

Having assignments act as calls for every random function is insane.
It can be done and is ok where the programmers decides this makes sense.
Your above stdio example is not such a case. [1]

artur

[1] But thanks for sharing it, I would have probably never thought of
    using a static opAssign otherwise...

   struct stdout {
      static void opAssign(T...)(T args) {
         import std.stdio;
         writeln(args);
      }
   }

   void main() {
      stdout = "It's a strange world";
   }


December 03, 2012
I had been trying to advance the phase to the next.
Now, an experimental pull request is here.
https://github.com/D-Programming-Language/dmd/pull/1311

----
This change can distinguish almost usages between property and non-property syntax

int func() { return 1; }
void func(int n) { }
@property int prop() { return 2; }
@property void prop(int n) { }
void main() {
  // Without -property switch, all lines can compile.
  // With -property switch:
  func();     // OK -> OK
  func(1);    // OK -> OK
  func;       // OK -> OK [*]
  func = 1;   // OK -> NG (fixed!)
  prop();     // OK -> NG (fixed!)
  prop(1);    // OK -> NG (fixed!)
  prop;       // OK -> OK
  prop = 1;   // OK -> OK
}

First exception is [*], keeping the line is necessary to allow UFCS chain
without redundant parentheses (e.g. r.map!(a=>a*2).array). It is acceptable
to me, at least.

----
I also implemented that calling function pointer which returned by property function.

@property foo(){ return (int n) => n * 2; }
auto n = foo(10);  // `foo` is resolved to property function call in advance
assert(n == 20);

But, we cannot support it immediately, because it will *always* introduce breaking of existing code.

- If enable always this feature, propfunc() is implicitly translated to
(propfunc())(),
  then much existing correct code without "-property" switch will break.
- If enable this only when -property switch is specified, a code propfunc()
will have
  _two_ meanings. When propfunc returns a function pointer,
  * If -property is on, propfunc() is translated to propfunc()(), then
    call returned function pointer and returns its result.
  * If -property is off, propfunc() is jsut call property function, then
    returns function pointer.

Changing compilation behavior by compile switch is bad. Then it is the second exception.

----
The third exception is in AddressExpression (&exp).

In current, both &func and &propfunc return their function pointers. Some
peoples argues
that the latter should return an address of the returned value of propfunc
after implementing more property enforcement, but I'm difficult to accept
that.

The root cause is: AddressExpression is just only one built-in feature for
getting an exact type of property function (Note that typeof(propfunc)
returns the type of propfunc result).

If compiler will always translate the code &propfunc to &(propfunc()),
we will lost a way to get an exact type of propfunc, and then
std.traits.FunctionTypeOf will never work for propfunc.

To resolve the issue, I have proposed a small enhancement for AddressExpression. http://d.puremagic.com/issues/show_bug.cgi?id=9062

It will distinguish &propfunc and &(propfunc), the former returns a function poiinter of propfunc, and the latter returns an address of propfunc result.

The real example about that is here. https://github.com/D-Programming-Language/phobos/pull/968/files#L0L1136

----
How about that?

Kenji Hara


December 03, 2012
On 12/2/12 1:49 AM, deadalnix wrote:
> On Tuesday, 20 November 2012 at 04:12:54 UTC, Andrei Alexandrescu wrote:
>> On 11/19/12 5:23 PM, Rob T wrote:
>>> I don't have an answer, but there may be more to the picture than we
>>> think.
>>
>> I agree. In particular I find it a specious argument to insist on
>> religiously associating "()" with function calling and the lack
>> thereof with variable access. I don't see myself, when seeing an
>> expression like "generator(x, y, z).map!(x => x * x)()", going like
>> "holy cow, good I saw those trailing parens, otherwise I would've
>> sworn it was a variable". Trailing parens in UFCS chains are just
>> warts, this is the reality. Let's deal with it.
>>
>>
>> Andrei
>
> And what do you think about map!(x => x * x) = generator(x, y, z) ?

I think that ought to be disallowed.

Andrei
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Top | Discussion index | About this forum | D home