January 05, 2019
On Sat, Jan 05, 2019 at 10:48:30PM +0000, Dgame via Digitalmars-d wrote: [...]
> 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]
> ----

Impressive!  Though we pretty much had to bring out the nuclear warhead to get here. :-D  By this point I wonder if it has already made the original reason for doing this moot compared to just directly importing the symbol! :-P


T

-- 
They pretend to pay us, and we pretend to work. -- Russian saying
January 06, 2019
On Saturday, 5 January 2019 at 23:44:31 UTC, H. S. Teoh wrote:
> On Sat, Jan 05, 2019 at 10:48:30PM +0000, Dgame via Digitalmars-d wrote: [...]
>> 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]
>> ----
>
> Impressive!  Though we pretty much had to bring out the nuclear warhead to get here. :-D  By this point I wonder if it has already made the original reason for doing this moot compared to just directly importing the symbol! :-P
>
>
> T

Nice, just surprised it took this long, I made the opDispatch snippet challenge in the blog nearly 2 years ago. I had assumed people would jump all over it. (like you now did in this thread).

https://dlang.org/blog/2017/02/13/a-new-import-idiom/
> Now then, is this the only solution? No. As a challenge to the reader, try to figure out what this does and, more importantly, its flaw. Can you fix it?
>
> static struct STD
> {
>   template opDispatch(string moduleName)
>   {
>     mixin("import opDispatch = std." ~ moduleName ~ ";");
>   }
> }

January 06, 2019
On Sunday, 6 January 2019 at 12:11:41 UTC, Daniel N wrote:
> On Saturday, 5 January 2019 at 23:44:31 UTC, H. S. Teoh wrote:
>> On Sat, Jan 05, 2019 at 10:48:30PM +0000, Dgame via Digitalmars-d wrote: [...]
>>> 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]
>>> ----
>>
>> Impressive!  Though we pretty much had to bring out the nuclear warhead to get here. :-D  By this point I wonder if it has already made the original reason for doing this moot compared to just directly importing the symbol! :-P
>>
>>
>> T
>
> Nice, just surprised it took this long, I made the opDispatch snippet challenge in the blog nearly 2 years ago. I had assumed people would jump all over it. (like you now did in this thread).
>

Really nice! I like it so much, I've taken the liberty to wrap it up as a dub package: https://code.dlang.org/packages/localimport.
As I'm a total noob on all this, please let me know if I messed anything up or stepped on anybody's toes with this.

FR
January 06, 2019
On Sunday, 6 January 2019 at 15:45:57 UTC, FR86 wrote:
>
> Really nice! I like it so much, I've taken the liberty to wrap it up as a dub package: https://code.dlang.org/packages/localimport.
> As I'm a total noob on all this, please let me know if I messed anything up or stepped on anybody's toes with this.
>
> FR

Please feel free to use it any way you wish. Boost/Public Domain etc, all fine.

Personally I prefer "static assert" over exceptions.


January 06, 2019
On Sunday, 6 January 2019 at 17:36:44 UTC, Daniel N wrote:

> Personally I prefer "static assert" over exceptions.

Makes sense! Updated to use static assert outside of unittests.
January 07, 2019
On Sunday, 6 January 2019 at 20:26:49 UTC, FR86 wrote:
> On Sunday, 6 January 2019 at 17:36:44 UTC, Daniel N wrote:
>
>> Personally I prefer "static assert" over exceptions.
>
> Makes sense! Updated to use static assert outside of unittests.

`version(unittest)` will also be defined if a user uses your library for testing his code. If you really want to, you could set a special version via dub, e.g.:

```
configuration "unittest" {
    version "LocalImportUnittest"
}
```

Also, you need to e.g. split up your test into two as otherwise you won't test whether the first part of the test (or the second for that matter) actually throws. You are currently doing an XOR in both parts.
January 07, 2019
On 1/5/19 5:48 PM, Dgame wrote:
> 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]
> ----

This is pretty awesome.

I ran a couple of experiments and the idiom seems to be lazy as expected, e.g. in the declaration:

void fun(T)() if (from.std.traits.isIntegral!T)
{
    from.std.stdio.writeln("Hallo");
}

neither std.traits nor std.stdio gets loaded if fun is not instantiated.

I took the liberty to ask Razvan Nitu to look into fixing https://issues.dlang.org/show_bug.cgi?id=17181.

I also asked Eduard Staniloiu to investigate using this idiom internally in Phobos so as to accumulate some experience with it. Dgame's implementation is a good start.

Since the implementation would (initially at least) be private, the presence of "from" in documentation would be awkward. So I suggest the glorious hack:

alias std = from.std;

so then things like std.traits.isIntegral and std.algorithm.comparison.min resolve and auto-load properly, while also standing beautifully in the documentation.


Andrei
January 07, 2019
On Monday, 7 January 2019 at 18:11:51 UTC, Seb wrote:
> `version(unittest)` will also be defined if a user uses your library for testing his code. If you really want to, you could set a special version via dub, e.g.:
>
> ```
> configuration "unittest" {
>     version "LocalImportUnittest"
> }
> ```

Done!

> Also, you need to e.g. split up your test into two as otherwise you won't test whether the first part of the test (or the second for that matter) actually throws. You are currently doing an XOR in both parts.

Oops! Fixed.

Thanks for the feedback, much appreciated!
January 08, 2019
On Monday, 7 January 2019 at 21:50:20 UTC, Andrei Alexandrescu wrote:
> On 1/5/19 5:48 PM, Dgame wrote:
[..]
> So I suggest the glorious hack:
>
> alias std = from.std;
>
> so then things like std.traits.isIntegral and std.algorithm.comparison.min resolve and auto-load properly, while also standing beautifully in the documentation.
>
>
> Andrei

I just started playing around with it, it might be no surprise,
but if you go further and start to make some local aliases inside main() like

alias writeln = std.stdio.writeln; // for convenience
string myvar ="Test";

You can user writeln(myvar) but not with UFCS: myvar.writeln;

I realized that UFCS would work only if the alias is defined outside of main();

Is this a bug or a feature? Don't know if this can be solved.

Regards mt.


Regards mt.
January 08, 2019
On Monday, 7 January 2019 at 21:50:20 UTC, Andrei Alexandrescu wrote:
> This is pretty awesome.
>
> Since the implementation would (initially at least) be private, the presence of "from" in documentation would be awkward. So I suggest the glorious hack:

I am probably in minority here, or I am misunderstand the purpose of this feature, but wouldn't such stuff be better put somewhere around the compiler/frontend rather than in the library with compile-time magic?

Maybe I am wrong, but if I were a complete outsider to D and saw this kind of mixin magic, I'd be definitely concerned. I wouldn't see it as "glorious hack", instead I'd view it as "wow, D is so bad, look how many tricks they do just to import std lib" :S