[Issue 8381] Uniform function call syntax (pseudo member) enhancement suggestions

2017-07-05 Thread via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=8381

Vladimir Panteleev  changed:

   What|Removed |Added

 Status|NEW |RESOLVED
 Resolution|--- |INVALID

--- Comment #8 from Vladimir Panteleev  ---
(In reply to Tommi from comment #0)
> So, I'm suggesting these two features to be added to the language:

Hello,

Changes to the language need to be proposed through the DIP process:

https://github.com/dlang/DIPs

Bugzilla is not the correct place for language enhancements.

If you still believe your proposal has merit, please submit a DIP. The current
DIP manager can assist you through the process.

--


[Issue 8381] Uniform function call syntax (pseudo member) enhancement suggestions

2015-06-09 Thread via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=8381

Andrei Alexandrescu  changed:

   What|Removed |Added

Version|unspecified |D2

--


[Issue 8381] Uniform function call syntax (pseudo member) enhancement suggestions

2012-07-12 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=8381



--- Comment #7 from David Piepgrass  2012-07-12 12:21:21 
PDT ---
> It almost looks like we're trying to pass MyType as first argument to the
> function, but because we can't pass type as function argument, we pass it as
> first template argument. But you're right that none of that is very obvious.
> Maybe the whole uniform function call syntax could have been implemented
> somehow differently so that it had been more intuitive to people new to the
> language.

Well, yeah, maybe. I could probably think of some alternatives that are a bit
more intuitive than UFCS. For example I think it would be nice to allow 
"alternate" interfaces to types, something like:

alias MyInt : int {
bool isPrime() const { ... }
}
MyInt x = 7;   writeln(x.isPrime()); // OK
int   y = x+1; writeln(y.isPrime()); // ERROR, no such function in "int"

>But I really mean type when I say, "extending the functionality of a type". I
>mean not only class but all user defined types as well, like enum, struct and
>union.

My proposal could easily include enums and structs, too:

static enum Goo { static Goo g() {...} }
static struct Hoo { static void f() {...} }

It reminds me that C# allows "new Hoo()" for structs even though they are not
allocated on the heap. If that existed in D then the "static new" part of my
proposal could work well for structs, too.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 8381] Uniform function call syntax (pseudo member) enhancement suggestions

2012-07-12 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=8381



--- Comment #6 from David Piepgrass  2012-07-12 12:06:36 
PDT ---
Argh, so many typos, I should be careful when I rename things...

> // Static helper method provides an easy way to create MyClass
> public static Foo LoadFrom(string filename, ...)
> However, the client didn't like that, and insisted that Create() should be a
> constructor "for consistency". I was able to rearrange things to make Create()
> into a constructor, but my code was a little clunkier that way.

s/MyClass/Foo/
s/Create/LoadFrom/

Oh how nice it would be if we could simply correct our posts.

> You could also argue that it's not obvious that:
> var.func(arg);
> 
> ...can "transform" itself into:
> func(var, arg);

That feature is used very often, so newcomers will learn it quickly. And it is
definitely a more obvious transformation than func!Type(...).

P.S. I'm just throwing it out there, but couldn't classes themselves be treated
as objects, a la Objective C? That could open the door to another approach, in
which UFCS applies to class objects.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 8381] Uniform function call syntax (pseudo member) enhancement suggestions

2012-07-12 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=8381



--- Comment #5 from Tommi  2012-07-12 10:50:58 PDT ---
One small point I forgot to mention about my lowering proposal, which is that
besides adding static pseudo-member functions, you can also add types. For
example:

struct WrapInt
{
int m_value;
}

template ValueType(T)
if (is(T == WrapInt))
{
alias int ValueType;
}

void main(string[] args)
{
WrapInt.ValueType value = 12;
 // gets lowered into: 
 // ValueType!WrapInt value = 12;
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 8381] Uniform function call syntax (pseudo member) enhancement suggestions

2012-07-12 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=8381


deadalnix  changed:

   What|Removed |Added

 CC||deadal...@gmail.com


--- Comment #4 from deadalnix  2012-07-12 10:23:56 PDT ---
(In reply to comment #3)
> (In reply to comment #1)
> > - The rule is non-obvious. How could a new developer possibly guess that 
> > this
> > happens?
> 
> You could also argue that it's not obvious that:
> var.func(arg);
> 
> ...can "transform" itself into:
> func(var, arg);
> 
> I don't think it's that much different to transform:
> MyType.func(arg);
> 
> ...into:
> func!(MyType)(arg);
> 

This is the most obvious way to transform that.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 8381] Uniform function call syntax (pseudo member) enhancement suggestions

2012-07-12 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=8381



--- Comment #3 from Tommi  2012-07-12 10:08:16 PDT ---
(In reply to comment #1)
> - The rule is non-obvious. How could a new developer possibly guess that this
> happens?

You could also argue that it's not obvious that:
var.func(arg);

...can "transform" itself into:
func(var, arg);

I don't think it's that much different to transform:
MyType.func(arg);

...into:
func!(MyType)(arg);

It almost looks like we're trying to pass MyType as first argument to the
function, but because we can't pass type as function argument, we pass it as
first template argument. But you're right that none of that is very obvious.
Maybe the whole uniform function call syntax could have been implemented
somehow differently so that it had been more intuitive to people new to the
language.


(In reply to comment #1)
> Supposing that I would like to extend the set of static members in class Foo.
> How about:
> 
> module A;
> // assuming "static class" does not already have any meaning?
> static class Foo {
> static void F();
> static int x;
> }

But I really mean type when I say, "extending the functionality of a type". I
mean not only class but all user defined types as well, like enum, struct and
union.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 8381] Uniform function call syntax (pseudo member) enhancement suggestions

2012-07-12 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=8381



--- Comment #2 from David Piepgrass  2012-07-12 09:24:36 
PDT ---
> (not merely a @disabled default constructor, but no constructor at all).
Also, declaring an instance of a static class is not possible either, so that
given

> module Q;
> static class Foo {
>static P.Foo new(Bar b, Baz z) {
>...
>return new P.Foo(...);
>}
>}

The meaning is unambiguous in:

Foo f = new Foo(Bar(...), Baz(...));
// equivalent to P.Foo f = Q.Foo.new(Bar(...), Baz(...));

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 8381] Uniform function call syntax (pseudo member) enhancement suggestions

2012-07-12 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=8381


David Piepgrass  changed:

   What|Removed |Added

 CC||qwertie...@gmail.com


--- Comment #1 from David Piepgrass  2012-07-12 09:11:28 
PDT ---
To some extent I like the goal of the proposal, but I don't like the
implementation:

- The rule is non-obvious. How could a new developer possibly guess that this
happens?
- It would get lowered to a call to a template function, but usually the
programmer wants to extend one specific type.

So I offer the following counterproposal:

1) Adding static member functions

Supposing that I would like to extend the set of static members in class Foo.
How about:

module A;
// assuming "static class" does not already have any meaning?
static class Foo {
static void F();
static int x;
}

This block defines members in a class namespace "Foo". If "regular class Foo"
is defined in module A then these static members go into the same class.
However, if the original Foo is defined in module B then "static class Foo"
goes into module A and is considered a separate class.

Now consider some code that tries to use F():

module C;
import A;
import B;
void code() { Foo.F(); }

Currently, the compiler complains that B.Foo and A.Foo conflict with each
other. I propose changing this rule when accessing static members. The compiler
does not need to declare a conflict as soon as it sees "Foo", instead it can
look for static members in ALL Foo classes, using the same anti-hijacking rules
that it uses for free-standing module functions.

The purpose of "static class" is not to facilitate this method lookup per se;
if A and B both contain non-static Foo classes, the compiler should still
search both classes for static members rather than giving an error immediately.
Rather, the main purpose of "static class" is to declare that the class has no
constructor (not merely a @disabled default constructor, but no constructor at
all). Therefore, "new Foo()" cannot mean "new A.Foo", leading the compiler to
the interpretation "new B.Foo". Also, multiple static classes can be defined
with the same name in the same module, and their contents are merged. 

IMO, when searching for static members, a class scope should pretty much behave
the same way as module scope. So the compiler should not report an ambiguous
call if the call has only one interpretation. In the above case, the compiler
should report an error if and only if a B.F() function exists.

One more thing, if module C declares a "class Foo" then it takes priority over
A.Foo and B.Foo. But if C declares "static class Foo" then C.Foo should allow
the same overloading behavior just described; thus "new Foo()" should still
mean "new B.Foo()" and "Foo.F()" should still mean "A.Foo.F()". I think an
equivalent way to say this is that, inside C, the lookup rules proceed as if
C.Foo were declared outside module C and imported into C.


2) Adding constructors aka "Constructors Considered Harmful"

Ahh, constructors, constructors. In my opinion the constructor design in most
languages including C++, C#, D and Java is flawed, because it exposes an
implementation detail that should not be exposed, namely, which class gets
allocated and when.

I offer you as "exhibit L" the Lazy class in the .NET framework. This
class's main purpose is to compute a value the first time you access it. For
example:

int x;
Lazy lazy = new Lazy(() => 7 * x);
x = 3;
x = lazy.Value; // 21
x = lazy.Value; // still 21 (Value is initialized only once)

There is an annoying issue though Lazy operates in some different modes, and
it also contains a member and extra code to aid debugging. So in addition to
holding the value itself and a reference to the initializer delegate, it's got
a couple of other member variables and the Value property has to check a couple
of things before it returns the value.

So what if, in the future, MS decided to optimize Lazy for its default mode
of operation, and factor out other modes into derived class(es)? Well, they
can't do that. If MS wants to return a LazyThreadSafe object (derived from
Lazy) when the user requests the thread-safe mode, they can't do that
because all the clients are saying "new Lazy", which can only return the exact
class Lazy and nothing else.

MS could add a static function, Lazy.New(...) but it's too late now that the
interface is already defined with all those public constructors.

As "exhibit 2", a.k.a. "exhibit Foo", I recently wrote a library where I needed
to provide a constructor that does a bunch of initialization work (that may
fail) before it actually creates the object. By far the most natural
implementation was a static member function:

// Constructor with dependency injection
public Foo(arg1, arg2, arg3)
{
}
// Static helper method provides an easy way to create MyClass
public static Foo LoadFrom(string file