January 05, 2019
On Saturday, 5 January 2019 at 04:06:45 UTC, Ethan wrote:
> [code]

That first compiles check is unnecessary.

This also gives stupid errors if you do something like std.stdio.wrteln( "It works!" ); eg.

onlineapp.d(23): Error: more initializers than fields (0) of from
January 04, 2019
On Fri, Jan 04, 2019 at 08:54:44PM -0500, Andrei Alexandrescu via Digitalmars-d wrote:
> On 1/4/19 8:11 AM, bauss wrote:
> > On Thursday, 3 January 2019 at 23:54:42 UTC, SrMordred wrote:
> > > struct _std
> > > {
> > >   template opDispatch(string moduleName)
> > >   {
> > >     mixin("import opDispatch = std." ~ moduleName ~ ";");
> > >   }
> > > }
> > 
> > 
> > There is nothing that's actually stopping you from just calling it std.
> > 
> > It will work just as fine.
> > 
> > That way you can end up with
> > 
> > std.stdio.writeln("...");
> > 
> > Instead of:
> > _std.stdio.writeln("...");
> 
> This is quite amazing.

It doesn't have to be tied to a specific root package. Just call it "autoimport", or something short like "from":

	struct from
	{
	  template opDispatch(string moduleName)
	  {
	    mixin("import opDispatch = " ~ moduleName ~ ";");
	  }
	}

Then just write:

	from.std.stdio.writeln("...");
	from.some.other.package.func(1, 2, 3);

and so on.


T

-- 
Doubtless it is a good thing to have an open mind, but a truly open mind should be open at both ends, like the food-pipe, with the capacity for excretion as well as absorption. -- Northrop Frye
January 05, 2019
On Fri, 04 Jan 2019 20:13:05 -0800, H. S. Teoh wrote:
> It doesn't have to be tied to a specific root package. Just call it "autoimport", or something short like "from":
> 
> 	struct from {
> 	  template opDispatch(string moduleName)
> 	  {
> 	    mixin("import opDispatch = " ~ moduleName ~ ";");
> 	  }
> 	}
> 
> Then just write:
> 
> 	from.std.stdio.writeln("...");

Error: module `std` is in file 'std.d' which cannot be read

You need the opDispatch to take the module name rather than a qualified package name. To fix that, you can write something like:

---
struct FromImpl(string prefix)
{
    template opDispatch(string ident)
    {
        enum qualified = prefix == "" ? ident : prefix ~ "." ~ ident;
        static if (__traits(compiles,
           {mixin("import ", qualified, ";");}))
        {
            mixin("import opDispatch = ", qualified, ";");
        }
        else
        {
            enum opDispatch = FromImpl!(qualified)();
        }
    }
}
enum from = FromImpl!""();
---

This is greedy, so it doesn't work for everything. Let's say you have:

  foo/
    package.d
    bar/
      baz.d

In this case, from.foo.bar.baz.someFunc() will find foo/package.d and look for a symbol it defines named bar. If it doesn't define that symbol, you're out of luck.

Reader exercise: is there a way to make this second case work? How does this interact with metaprogramming, and what sorts of precautions should you take?
January 05, 2019
On Sat, Jan 05, 2019 at 05:57:57AM +0000, Neia Neutuladh via Digitalmars-d wrote:
> On Fri, 04 Jan 2019 20:13:05 -0800, H. S. Teoh wrote:
[...]
> > 	struct from {
> > 	  template opDispatch(string moduleName)
> > 	  {
> > 	    mixin("import opDispatch = " ~ moduleName ~ ";");
> > 	  }
> > 	}
> > 
> > Then just write:
> > 
> > 	from.std.stdio.writeln("...");
> 
> Error: module `std` is in file 'std.d' which cannot be read
> 
> You need the opDispatch to take the module name rather than a qualified package name.

Hmph.  But in that case, doesn't that mean that the original definition of _std doesn't work with Phobos subpackages, like std.algorithm, because it would be trying to lookup the symbol in the package rather than the module? So something like _std.algorithm.searching.find would fail, because `searching.find` cannot be found in std/algorithm/package.d.


[...]
> ---
> struct FromImpl(string prefix)
> {
>     template opDispatch(string ident)
>     {
>         enum qualified = prefix == "" ? ident : prefix ~ "." ~ ident;
>         static if (__traits(compiles,
>            {mixin("import ", qualified, ";");}))
>         {
>             mixin("import opDispatch = ", qualified, ";");
>         }
>         else
>         {
>             enum opDispatch = FromImpl!(qualified)();
>         }
>     }
> }
> enum from = FromImpl!""();
> ---

Interesting.


> This is greedy, so it doesn't work for everything. Let's say you have:
> 
>   foo/
>     package.d
>     bar/
>       baz.d
> 
> In this case, from.foo.bar.baz.someFunc() will find foo/package.d and look for a symbol it defines named bar. If it doesn't define that symbol, you're out of luck.
> 
> Reader exercise: is there a way to make this second case work? How does this interact with metaprogramming, and what sorts of precautions should you take?

Hmm. Couldn't you make it work by making it lazy? I.e., have opDispatch return a struct that encapsulates a partial package path, and that contains a further opDispatch to resolve the next component in the qualified name, and that only resolves to the actual symbol when it actually references an actual symbol?


T

-- 
There's light at the end of the tunnel. It's the oncoming train.
January 05, 2019
On 1/4/19 11:13 PM, H. S. Teoh wrote:
> On Fri, Jan 04, 2019 at 08:54:44PM -0500, Andrei Alexandrescu via Digitalmars-d wrote:
>> On 1/4/19 8:11 AM, bauss wrote:
>>> On Thursday, 3 January 2019 at 23:54:42 UTC, SrMordred wrote:
>>>> struct _std
>>>> {
>>>>    template opDispatch(string moduleName)
>>>>    {
>>>>      mixin("import opDispatch = std." ~ moduleName ~ ";");
>>>>    }
>>>> }
>>>
>>>
>>> There is nothing that's actually stopping you from just calling it
>>> std.
>>>
>>> It will work just as fine.
>>>
>>> That way you can end up with
>>>
>>> std.stdio.writeln("...");
>>>
>>> Instead of:
>>> _std.stdio.writeln("...");
>>
>> This is quite amazing.
> 
> It doesn't have to be tied to a specific root package. Just call it
> "autoimport", or something short like "from":
> 
> 	struct from
> 	{
> 	  template opDispatch(string moduleName)
> 	  {
> 	    mixin("import opDispatch = " ~ moduleName ~ ";");
> 	  }
> 	}
> 
> Then just write:
> 
> 	from.std.stdio.writeln("...");
> 	from.some.other.package.func(1, 2, 3);
> 
> and so on.
> 
> 
> T
> 

Cool. Here's the previous clunkier implementation:

https://github.com/dlang/druntime/pull/1756

And here's the bug preventing it:

https://issues.dlang.org/show_bug.cgi?id=17181

Is the bug also affecting this newly invented idiom?


Andrei
January 05, 2019
On Sat, 05 Jan 2019 06:52:14 -0800, H. S. Teoh wrote:
> Hmm. Couldn't you make it work by making it lazy? I.e., have opDispatch return a struct that encapsulates a partial package path, and that contains a further opDispatch to resolve the next component in the qualified name, and that only resolves to the actual symbol when it actually references an actual symbol?

Right! However, you can't tell the difference between accessing a symbol that doesn't exist and accessing a package.

You'll see a difference in things like:

    static if (is(typeof(from.std.socket.Sockte)))

In this lazy model, that's going to be a FromImpl!"std.socket.Sockte" and will pass. In the eager model, it would be std.socket.Sockte, which doesn't exist.
January 05, 2019
On 1/5/19 12:30 PM, Neia Neutuladh wrote:
> On Sat, 05 Jan 2019 06:52:14 -0800, H. S. Teoh wrote:
>> Hmm. Couldn't you make it work by making it lazy? I.e., have opDispatch
>> return a struct that encapsulates a partial package path, and that
>> contains a further opDispatch to resolve the next component in the
>> qualified name, and that only resolves to the actual symbol when it
>> actually references an actual symbol?
> 
> Right! However, you can't tell the difference between accessing a symbol
> that doesn't exist and accessing a package.

Hmmm... we should have introspection mechanisms to distinguish these cases.

January 05, 2019
On Saturday, 5 January 2019 at 17:30:15 UTC, Neia Neutuladh wrote:
> On Sat, 05 Jan 2019 06:52:14 -0800, H. S. Teoh wrote:
>> Hmm. Couldn't you make it work by making it lazy? I.e., have opDispatch return a struct that encapsulates a partial package path, and that contains a further opDispatch to resolve the next component in the qualified name, and that only resolves to the actual symbol when it actually references an actual symbol?
>
> Right! However, you can't tell the difference between accessing a symbol that doesn't exist and accessing a package.
>
> You'll see a difference in things like:
>
>     static if (is(typeof(from.std.socket.Sockte)))
>
> In this lazy model, that's going to be a FromImpl!"std.socket.Sockte" and will pass. In the eager model, it would be std.socket.Sockte, which doesn't exist.

I'm curious about that. Would that work or did I miss something?

----
template isSymbolInModule(string module_, string symbol)
{
    static if (__traits(compiles, { mixin("import ", module_, ";"); })) {
        enum import_ = module_ ~ ":" ~ symbol;
        enum isSymbolInModule = __traits(compiles, { mixin("import ", import_, ";"); });
    } else {
        enum isSymbolInModule = false;
    }
}

struct FromImpl(string module_)
{
    template opDispatch(string symbol)
    {
        static if (isSymbolInModule!(module_, symbol)) {
            mixin("import ", module_, "; alias opDispatch = ", symbol, ";");
        } else {
            enum import_ = module_.length == 0 ? symbol : module_ ~ "." ~ symbol;
            enum opDispatch = FromImpl!(import_)();
        }
    }
}

from.std.stdio.writeln("Hallo");
auto _ = from.std.datetime.stopwatch.AutoStart.yes;
----
January 05, 2019
On Sat, 05 Jan 2019 21:14:37 +0000, Dgame wrote:
> I'm curious about that. Would that work or did I miss something?

In your version, I might write:

  from.std.stdio.thisFunctionDoesNotExist("Hallo");

And the error I would get is:

  Error: struct FromImpl does not overload ()
January 05, 2019
On Saturday, 5 January 2019 at 21:36:10 UTC, Neia Neutuladh wrote:
> On Sat, 05 Jan 2019 21:14:37 +0000, Dgame wrote:
>> I'm curious about that. Would that work or did I miss something?
>
> In your version, I might write:
>
>   from.std.stdio.thisFunctionDoesNotExist("Hallo");
>
> And the error I would get is:
>
>   Error: struct FromImpl does not overload ()

True.. What about:

----
template isModuleImport(string import_)
{
    enum isModuleImport = __traits(compiles, { mixin("import ", import_, ";"); });
}

template isSymbolInModule(string module_, string symbol)
{
    static if (isModuleImport!module_) {
        enum import_ = module_ ~ ":" ~ symbol;
        enum isSymbolInModule = __traits(compiles, { mixin("import ", import_, ";"); });
    } else {
        enum isSymbolInModule = false;
    }
}

template FailedSymbol(string symbol, string module_)
{
    auto FailedSymbol(Args...)(auto ref Args args)
    {
        assert(0, "Symbol \"" ~ symbol ~ "\" not found in " ~ module_);
    }
}

struct FromImpl(string module_)
{
    template opDispatch(string symbol)
    {
        static if (isSymbolInModule!(module_, symbol)) {
            mixin("import ", module_, "; alias opDispatch = ", symbol, ";");
        } else {
            static if (module_.length == 0) {
            	enum opDispatch = FromImpl!(symbol)();
            } else {
                enum import_ = module_ ~ "." ~ symbol;
                static if (isModuleImport!import_) {
               		enum opDispatch = FromImpl!(import_)();
                } else {
                    alias opDispatch = FailedSymbol!(symbol, module_);
                }
            }
        }
    }
}

enum from = FromImpl!null();

void main()
{
    from.std.stdio.writeln("Hallo");
    auto _ = from.std.datetime.stopwatch.AutoStart.yes;
    from.std.stdio.thisFunctionDoesNotExist("Hallo");
    from.std.stdio.thisFunctionDoesNotExist(42);
}
----

Output:

----
Hallo
core.exception.AssertError@onlineapp.d(20): Symbol "thisFunctionDoesNotExist" not found in std.stdio
----------------
??:? _d_assert_msg [0x3c00dc54]
onlineapp.d:20 pure nothrow @nogc @safe void onlineapp.FailedSymbol!("thisFunctionDoesNotExist", "std.stdio").FailedSymbol!(immutable(char)[]).FailedSymbol(immutable(char)[]) [0x3c00ceac]
onlineapp.d:52 _Dmain [0x3c00c8c3]
----