www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Poll: what should this program do?

reply Paul Backus <snarwin gmail.com> writes:
Here's a weird little program that came up in a recent Discord 
discussion:

     template fun(T)
     {
         string fun(T) => fun("hi");
         string fun(string) => "inner";
     }
     string fun(string) => "outer";

     void main()
     {
         import std.stdio;
         writeln(fun(123));
     }


**What SHOULD this program do?**

1. Print "inner".
2. Print "outer".
3. It shouldn't compile.

**What do you think it ACTUALLY does?**

1. Print "inner".
2. Print "outer".
3. It doesn't compile.
Mar 18
next sibling parent monkyyy <crazymonkyyy gmail.com> writes:
On Wednesday, 19 March 2025 at 03:40:28 UTC, Paul Backus wrote:
 Here's a weird little program that came up in a recent Discord 
 discussion:

     template fun(T)
     {
         string fun(T) => fun("hi");
         string fun(string) => "inner";
     }
     string fun(string) => "outer";

     void main()
     {
         import std.stdio;
         writeln(fun(123));
     }


 **What SHOULD this program do?**

 1. Print "inner".
 2. Print "outer".
 3. It shouldn't compile.

 **What do you think it ACTUALLY does?**

 1. Print "inner".
 2. Print "outer".
 3. It doesn't compile.
It should print outer and does print outer you didnt actually introduce ambiguity ```d template fun(alias T) { string fun(T) => fun("hi"); string fun(string) => "inner"; } string fun(string) => "outer"; void main() { import std.stdio; writeln(fun(123)); } ``` fails
Mar 18
prev sibling next sibling parent reply Ogion <ogion.art gmail.com> writes:
On Wednesday, 19 March 2025 at 03:40:28 UTC, Paul Backus wrote:

 **What SHOULD this program do?**

 **What do you think it ACTUALLY does?**
It should print “outer”, and it actually does. Obviously, at first I expected it to print: “inner”. But when I saw the result and checked the spec, I think that it works correctly. There are three non-obvious things ging in here. Number one: `fun(T).fun(string)` is not a regular function, it’s a template. So it doesn’t collide with globally-defined `fun(string)`. This is why this program compiles. Number two: inside eponymous template `fun`, `fun` refers to the template itself, not to its members. This gives a different result: ```D template fun(T) { alias fun = f; string f(int) => f("hi"); string f(string) => "inner"; } string f(string) => "outer"; void main() { import std.stdio; writeln(fun!int(123)); // sorry, IFTI no longer works } ``` Number three: using a type instead of template parameter (of the same type) is enough to break [implicit instantiation](https://dlang.org/spec/template.html#ifti-restrictions): ```D template fun(T) { string fun(string) => "inner"; } void main() { import std.stdio; writeln(fun("hi")); // error writeln(fun!string("hi")); // works } ``` There are many other ways to break IFTI: ```D template fun(T) { alias fun = fun; string f(T) => "inner"; } ``` ```D template fun(T) { template fun(T) { string fun(T) => "inner"; } } ``` I guess it can’t be helped. Usually, though, IFTI failure results in error. In this program, it leads to unforeseen behavior. But such is life on templates.
Mar 19
next sibling parent Dukc <ajieskola gmail.com> writes:
On Wednesday, 19 March 2025 at 10:31:36 UTC, Ogion wrote:
 Number two: inside eponymous template `fun`, `fun` refers to 
 the template itself, not to its members. This gives a different 
 result:
Well duh, I see how this causes the program to print "outer", but is this actually how it *should* be? If, why?
Mar 19
prev sibling next sibling parent Paul Backus <snarwin gmail.com> writes:
On Wednesday, 19 March 2025 at 10:31:36 UTC, Ogion wrote:
 Number two: inside eponymous template `fun`, `fun` refers to 
 the template itself, not to its members.
Sometimes...but not all the time. Check this out: template fun(T) { // call via function pointer string fun(T) => (&fun)("hi"); string fun(string) => "inner"; } string fun(string) => "outer"; void main() { import std.stdio; writeln(fun(123)); }
Mar 19
prev sibling parent Max Samukha <maxsamukha gmail.com> writes:
On Wednesday, 19 March 2025 at 10:31:36 UTC, Ogion wrote:

 Number two: inside eponymous template `fun`, `fun` refers to 
 the template itself, not to its members.
That's what I don't like. I'd prefer it to refer to the members of the template instance unless qualified.
Mar 19
prev sibling next sibling parent Dukc <ajieskola gmail.com> writes:
On Wednesday, 19 March 2025 at 03:40:28 UTC, Paul Backus wrote:
 Here's a weird little program that came up in a recent Discord 
 discussion:

     template fun(T)
     {
         string fun(T) => fun("hi");
         string fun(string) => "inner";
     }
     string fun(string) => "outer";

     void main()
     {
         import std.stdio;
         writeln(fun(123));
     }


 **What SHOULD this program do?**
Print "inner". Local symbol should hide the module-scope symbol, and "inner" printer is local from where `fun("hi")` is called. [The spec says](https://dlang.org/spec/function.html#function-overloading) that function overloading rules should only apply to functions in the same scope.
 **What do you think it ACTUALLY does?**
No idea. What I think it ought to do would be my expectation but the fact you posted this as a riddle hints it maybe doesn't work like that.
Mar 19
prev sibling next sibling parent Basile B. <b2.temp gmx.com> writes:
On Wednesday, 19 March 2025 at 03:40:28 UTC, Paul Backus wrote:
 Here's a weird little program that came up in a recent Discord 
 discussion:

     template fun(T)
     {
         string fun(T) => fun("hi");
         string fun(string) => "inner";
     }
     string fun(string) => "outer";

     void main()
     {
         import std.stdio;
         writeln(fun(123));
     }
What an overload-set nightmare.
 **What SHOULD this program do?**

 1. Print "inner".
 2. Print "outer".
 3. It shouldn't compile.
3 because two candidates of the set match.
 **What do you think it ACTUALLY does?**

 1. Print "inner".
 2. Print "outer".
 3. It doesn't compile.
I play the game, I haven't compiled the thing but I'd say "hi".
Mar 20
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 3/19/25 04:40, Paul Backus wrote:
 Here's a weird little program that came up in a recent Discord discussion:
 
      template fun(T)
      {
          string fun(T) => fun("hi");
          string fun(string) => "inner";
      }
      string fun(string) => "outer";
 
      void main()
      {
          import std.stdio;
          writeln(fun(123));
      }
 
 
 **What SHOULD this program do?**
 
 1. Print "inner".
 2. Print "outer".
 3. It shouldn't compile.
 ...
According to the documentation, IFTI wouldn't really apply at all because the first declaration is not a function template. Of course, what happens in practice is different. (But with the same result here.)
 **What do you think it ACTUALLY does?**
 
 1. Print "inner".
 2. Print "outer".
 3. It doesn't compile.
Maybe "stack overflow' should have been one of the options ;). It prints "outer", because IFTI is considered a worse match due to `T` being deduced. I don't think this behavior is documented. (But if you do `template foo()` and replace `T` with `string` in the body, you will get an ambiguity error.) This is another fun case: ```d template fun(T) { string fun(string) => "first"; string fun(const(T)) => fun("second"); } pragma(msg, fun("123")); ``` ```d template fun(T=string) { string fun(string) => "first"; string fun(const(T)) => "second"; } pragma(msg, fun("123")); ```
Mar 20