digitalmars.D - D import idiom compilation time
- SrMordred (18/18) Jan 03 2019 There is a veredict about the compilation speedup of the "New
- Jonathan Marler (29/47) Jan 03 2019 Yes.
- Jonathan Marler (9/60) Jan 03 2019 I should clarify. It depends what type of code you are writing.
- Rubn (4/22) Jan 04 2019 I like this idiom way more than the other nasty from!"..."
- Simen =?UTF-8?B?S2rDpnLDpXM=?= (38/65) Jan 04 2019 The struct could of course be templated:
- Andrei Alexandrescu (4/4) Jan 04 2019 On 1/4/19 1:04 PM, Simen Kjærås wrote:
- bauss (8/15) Jan 04 2019 There is nothing that's actually stopping you from just calling
- Andrei Alexandrescu (2/22) Jan 04 2019 This is quite amazing.
- H. S. Teoh (17/41) Jan 04 2019 It doesn't have to be tied to a specific root package. Just call it
- Neia Neutuladh (34/47) Jan 04 2019 Error: module `std` is in file 'std.d' which cannot be read
- H. S. Teoh (18/67) Jan 05 2019 Hmph. But in that case, doesn't that mean that the original definition
- Neia Neutuladh (8/13) Jan 05 2019 Right! However, you can't tell the difference between accessing a symbol...
- Andrei Alexandrescu (2/11) Jan 05 2019 Hmmm... we should have introspection mechanisms to distinguish these cas...
- Dgame (31/45) Jan 05 2019 I'm curious about that. Would that work or did I miss something?
- Neia Neutuladh (5/6) Jan 05 2019 In your version, I might write:
- Dgame (69/76) Jan 05 2019 True.. What about:
- H. S. Teoh (9/23) Jan 05 2019 Impressive! Though we pretty much had to bring out the nuclear warhead
- Daniel N (5/36) Jan 06 2019 Nice, just surprised it took this long, I made the opDispatch
- Andrei Alexandrescu (22/109) Jan 07 2019 This is pretty awesome.
- Martin Tschierschke (14/21) Jan 08 2019 [..]
- Adam D. Ruppe (7/10) Jan 08 2019 It is by design - UFCS only considered for global symbols. The
- Martin Tschierschke (4/9) Jan 08 2019 So, as a result I can conclude, that real local imports don't
- H. S. Teoh (23/34) Jan 08 2019 Not true. This works:
- Martin Tschierschke (5/28) Jan 08 2019 OK. Thank you!
- H. S. Teoh (40/42) Jan 08 2019 [...]
- JN (10/14) Jan 08 2019 I am probably in minority here, or I am misunderstand the purpose
- Johan Engelen (8/19) Jan 08 2019 FYI: at the end of last year Eyal (Weka) and Andrei (and me a
- Jonathan M Davis (11/31) Jan 08 2019 Yeah, Walter has expressed interest in having lazy imports in the past (...
- Jonathan Marler (10/31) Jan 09 2019 Make sure whoever works on it is aware of this:
- Dgame (13/23) Jan 09 2019 Maybe I'm missing something, but wouldn't it be possible to lazy
- Neia Neutuladh (6/10) Jan 09 2019 If you import two modules and both define functions named `write`, it is...
- Jonathan Marler (20/31) Jan 09 2019 That's right. Basically it boils down to this, as soon as you
- Nick Treleaven (4/7) Jan 08 2019 Apart from compiler overhead, this seems to make `static import`
- Andrei Alexandrescu (7/54) Jan 05 2019 Cool. Here's the previous clunkier implementation:
There is a veredict about the compilation speedup of the "New Import Idiom"? Currently i´m using it this way: struct _std { template opDispatch(string moduleName) { mixin("import opDispatch = std." ~ moduleName ~ ";"); } } ... //if used single time on scope. _std.algorithm.max(a,b); My question is that, in the long run, this will be worth the compilation time gains, or is just negligible and I should just import the normal way. (and keep the code more sane) Thanks!
Jan 03 2019
On Thursday, 3 January 2019 at 23:54:42 UTC, SrMordred wrote:There is a veredict about the compilation speedup of the "New Import Idiom"? Currently i´m using it this way: struct _std { template opDispatch(string moduleName) { mixin("import opDispatch = std." ~ moduleName ~ ";"); } } ... //if used single time on scope. _std.algorithm.max(a,b); My question is that, in the long run, this will be worth the compilation time gains, or is just negligible and I should just import the normal way. (and keep the code more sane) Thanks!Yes. --- testPerf.d struct fromStd { template opDispatch(string moduleName) { mixin("import opDispatch = std." ~ moduleName ~ ";"); } } version (UseFrom) { auto foo(T)(T arg) if (fromStd.typecons.isBitFlagEnum!T) { return arg; } } else { import std.typecons : isBitFlagEnum; auto foo(T)(T arg) if (isBitFlagEnum!T) { return arg; } } $ time dmd -c testperf.d real 0m0.050s $ time dmd -c -version=UseFrom testperf.d real 0m0.016s
Jan 03 2019
On Friday, 4 January 2019 at 02:43:01 UTC, Jonathan Marler wrote:On Thursday, 3 January 2019 at 23:54:42 UTC, SrMordred wrote:I should clarify. It depends what type of code you are writing. If you are writing library code in which only small parts of modules may be used then importing this way will allow apps to use your library while only importing the modules they need. If you are writing program code where you don't need to expose subsets of code to other modules, you just want to use library code then in most cases there's no benefit to lazily importing other modules since you're always going to need them.There is a veredict about the compilation speedup of the "New Import Idiom"? Currently i´m using it this way: struct _std { template opDispatch(string moduleName) { mixin("import opDispatch = std." ~ moduleName ~ ";"); } } ... //if used single time on scope. _std.algorithm.max(a,b); My question is that, in the long run, this will be worth the compilation time gains, or is just negligible and I should just import the normal way. (and keep the code more sane) Thanks!Yes. --- testPerf.d struct fromStd { template opDispatch(string moduleName) { mixin("import opDispatch = std." ~ moduleName ~ ";"); } } version (UseFrom) { auto foo(T)(T arg) if (fromStd.typecons.isBitFlagEnum!T) { return arg; } } else { import std.typecons : isBitFlagEnum; auto foo(T)(T arg) if (isBitFlagEnum!T) { return arg; } } $ time dmd -c testperf.d real 0m0.050s $ time dmd -c -version=UseFrom testperf.d real 0m0.016s
Jan 03 2019
On Thursday, 3 January 2019 at 23:54:42 UTC, SrMordred wrote:There is a veredict about the compilation speedup of the "New Import Idiom"? Currently i´m using it this way: struct _std { template opDispatch(string moduleName) { mixin("import opDispatch = std." ~ moduleName ~ ";"); } } ... //if used single time on scope. _std.algorithm.max(a,b); My question is that, in the long run, this will be worth the compilation time gains, or is just negligible and I should just import the normal way. (and keep the code more sane) Thanks!I like this idiom way more than the other nasty from!"..." syntax. Though you need to define a struct for any library you'd want to use it with, not that big of a deal. Thanks for sharing.
Jan 04 2019
On Friday, 4 January 2019 at 13:07:14 UTC, Rubn wrote:On Thursday, 3 January 2019 at 23:54:42 UTC, SrMordred wrote:The struct could of course be templated: struct from(string namespace) { template opDispatch(string subnamespace) { mixin("import opDispatch = "~namespace~"."~subnamespace~";"); } } unittest { alias std = from!"std"; std.stdio.writeln("ohai"); } And slightly more fancy, for those pesky nested packages: struct from(string namespace) { static if (__traits(compiles, { mixin("import "~namespace~";"); })) { mixin("import __from = "~namespace~";"); } template opDispatch(string subnamespace) { static if (__traits(compiles, { mixin("import "~namespace~"."~subnamespace~";"); })) { alias opDispatch = .from!(namespace~"."~subnamespace); } else { mixin("alias opDispatch = __from."~subnamespace~";"); } } } unittest { alias std = from!"std"; std.stdio.writeln("ohai"); // This would be impossible with the first version: static assert(std.range.primitives.isInputRange!(int[])); // As would single-level imports: alias myLibrary = from!"myLibrary"; myLibrary.someFunction(); } -- SimenThere is a veredict about the compilation speedup of the "New Import Idiom"? Currently i´m using it this way: struct _std { template opDispatch(string moduleName) { mixin("import opDispatch = std." ~ moduleName ~ ";"); } } ... //if used single time on scope. _std.algorithm.max(a,b); My question is that, in the long run, this will be worth the compilation time gains, or is just negligible and I should just import the normal way. (and keep the code more sane) Thanks!I like this idiom way more than the other nasty from!"..." syntax. Though you need to define a struct for any library you'd want to use it with, not that big of a deal. Thanks for sharing.
Jan 04 2019
On 1/4/19 1:04 PM, Simen Kjærås wrote: [snip] So I guess we could define a short module called "std.autostd" such that all uses of std.xxx would be resolved. Wow,
Jan 04 2019
On Saturday, 5 January 2019 at 01:58:15 UTC, Andrei Alexandrescu wrote:On 1/4/19 1:04 PM, Simen Kjærås wrote: [snip] So I guess we could define a short module called "std.autostd" such that all uses of std.xxx would be resolved. Wow,+1, awesome idea. - Elias
Jan 04 2019
On Saturday, 5 January 2019 at 01:58:15 UTC, Andrei Alexandrescu wrote:On 1/4/19 1:04 PM, Simen Kjærås wrote: [snip] So I guess we could define a short module called "std.autostd" such that all uses of std.xxx would be resolved. Wow,Looking at the above examples, and my own programming patterns lately. Every time I need something, I add it to my import statement, ie import std.algorithm : min, max, map, remove, sort; Having each invocation import only that symbol defined at the end would be ideal. Something like: struct from( string thismodule ) { template opDispatch( string symbol ) { static if( __traits( compiles, { mixin( "import " ~ thismodule ~ ";" ); } ) && __traits( compiles, { mixin( "import " ~ thismodule ~ " : " ~ symbol ~ ";" ); } ) ) { mixin( "import " ~ thismodule ~ " : " ~ symbol ~ ";"); mixin( "alias opDispatch = " ~ symbol ~ ";" ); } else { alias opDispatch = from!( thismodule ~ "." ~ symbol ); } } } int main( string[] args ) { alias std = from!"std"; std.stdio.writeln( "It works!" ); return 0; }
Jan 04 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
Jan 04 2019
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("...");
Jan 04 2019
On 1/4/19 8:11 AM, bauss wrote:On Thursday, 3 January 2019 at 23:54:42 UTC, SrMordred wrote:This is quite amazing.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("...");
Jan 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: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 FryeOn Thursday, 3 January 2019 at 23:54:42 UTC, SrMordred wrote:This is quite amazing.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("...");
Jan 04 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?
Jan 04 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:[...]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 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.--- 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.
Jan 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.
Jan 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:Hmmm... we should have introspection mechanisms to distinguish these cases.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.
Jan 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: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; ----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.
Jan 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 ()
Jan 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: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] ----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 ()
Jan 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
Jan 05 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: [...]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/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 TNow 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 ~ ";"); } }
Jan 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: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. FROn Sat, Jan 05, 2019 at 10:48:30PM +0000, Dgame via Digitalmars-d wrote: [...]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).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
Jan 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. FRPlease feel free to use it any way you wish. Boost/Public Domain etc, all fine. Personally I prefer "static assert" over exceptions.
Jan 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.
Jan 06 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:`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.Personally I prefer "static assert" over exceptions.Makes sense! Updated to use static assert outside of unittests.
Jan 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!
Jan 07 2019
On 1/5/19 5:48 PM, Dgame wrote:On Saturday, 5 January 2019 at 21:36:10 UTC, Neia Neutuladh wrote: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. AndreiOn Sat, 05 Jan 2019 21:14:37 +0000, Dgame wrote: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] ----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 ()
Jan 07 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. AndreiI 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.
Jan 08 2019
On Tuesday, 8 January 2019 at 10:54:24 UTC, Martin Tschierschke wrote: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.It is by design - UFCS only considered for global symbols. The idea is to simplify the reasoning process for finding .members by eliminating local scopes from the search (supposed to make ide stuff easier, etc) Whether this is good design or not is left up to the reader.
Jan 08 2019
On Tuesday, 8 January 2019 at 13:40:51 UTC, Adam D. Ruppe wrote: [...]It is by design - UFCS only considered for global symbols. The idea is to simplify the reasoning process for finding .members by eliminating local scopes from the search (supposed to make ide stuff easier, etc) Whether this is good design or not is left up to the reader.So, as a result I can conclude, that real local imports don't work togethter with UFCS, and this is disabling any chaining.
Jan 08 2019
On Tue, Jan 08, 2019 at 02:13:21PM +0000, Martin Tschierschke via Digitalmars-d wrote:On Tuesday, 8 January 2019 at 13:40:51 UTC, Adam D. Ruppe wrote: [...]Not true. This works: void main() { // N.B.: local imports import std.array; import std.algorithm; import std.conv; import std.stdio; // N.B.: UFCS chaining "abcdef".map!(e => cast(int) (e - 'a')) .filter!(e => e < 4) .map!(e => cast(dchar) (e + 'm')) .to!string .writeln; } To state more accurately what Adam said, UFCS is considered for *module-level* symbols. Meaning, the requirement is applied at the site of definition (it has to be at the top *level* in the module where it's defined) rather than the site of import (which can be in a local *scope*). T -- What is Matter, what is Mind? Never Mind, it doesn't Matter.It is by design - UFCS only considered for global symbols. The idea is to simplify the reasoning process for finding .members by eliminating local scopes from the search (supposed to make ide stuff easier, etc) Whether this is good design or not is left up to the reader.So, as a result I can conclude, that real local imports don't work togethter with UFCS, and this is disabling any chaining.
Jan 08 2019
On Tuesday, 8 January 2019 at 14:28:47 UTC, H. S. Teoh wrote:On Tue, Jan 08, 2019 at 02:13:21PM +0000, Martin Tschierschke via Digitalmars-d wrote:OK. Thank you! With "real local import" I was referring to the "new import idiom" in this thread, provided by localimport.dub.pm mt.[...]Not true. This works: void main() { // N.B.: local imports import std.array; import std.algorithm; import std.conv; import std.stdio; // N.B.: UFCS chaining "abcdef".map!(e => cast(int) (e - 'a')) .filter!(e => e < 4) .map!(e => cast(dchar) (e + 'm')) .to!string .writeln; } To state more accurately what Adam said, UFCS is considered for *module-level* symbols. Meaning, the requirement is applied at the site of definition (it has to be at the top *level* in the module where it's defined) rather than the site of import (which can be in a local *scope*). T
Jan 08 2019
On Tue, Jan 08, 2019 at 03:18:03PM +0000, Martin Tschierschke via Digitalmars-d wrote: [...]With "real local import" I was referring to the "new import idiom" in this thread, provided by localimport.dub.pm[...] The intent of that import idiom is an import whose scope is limited to the expression it's in. It's a way of pulling in a specific symbol without "polluting" the surrounding scope. E.g. currently, if you have a module-scope declaration that requires an imported symbol, you have no choice but to import the symbol into the containing scope: // This import line is required otherwise the sig constraint // won't work. import std.range.primitives : isInputRange; auto myRangeFunc(R)(R range) if (isInputRange!R) { ... } If this is the only function in a module of say 100 functions that requires std.range.primitives, it seems wasteful to import it into the entire module's scope. With the new import idiom, we can do this: // N.B.: no more imports in module scope! auto myRangeFunc(R)(R range) if (from.std.range.isInputRange!R) { ... } Which also makes the declaration carry it's own import dependencies, so when you decide to refactor and move this function into another module, you'll never have to worry about also moving/copying the global import statement. This is the primary use case of this idiom. If you actually need the import symbols into the containing scope, just use the built-in import statement instead! :-D auto myRangeFunc(R)(R range) if (from.std.range.isInputRange!R) { // We need std.uni in this function, so just pull it // into the function scope. No need to pull out the // expression-local import warhead! import std.uni : isWhite; while (!range.empty && isWhite(range.front)) range.popFront; ... // more uses of isWhite here ... } T -- LINUX = Lousy Interface for Nefarious Unix Xenophobes.
Jan 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
Jan 08 2019
On Tuesday, 8 January 2019 at 13:39:48 UTC, JN wrote:On Monday, 7 January 2019 at 21:50:20 UTC, Andrei Alexandrescu wrote:FYI: at the end of last year Eyal (Weka) and Andrei (and me a little bit) have been discussing lazy importing (full import) of symbols by the compiler. We hope to have a student work on this. Indeed I agree with you: the compiler could do (some of) this stuff, and because the rewards seem large it makes sense to indeed have the compiler do it. -JohanThis 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?
Jan 08 2019
On Tuesday, January 8, 2019 7:40:47 AM MST Johan Engelen via Digitalmars-d wrote:On Tuesday, 8 January 2019 at 13:39:48 UTC, JN wrote:Yeah, Walter has expressed interest in having lazy imports in the past (e.g. he talked about it when Liran was complaining about importing issues at dconf a few years ago). So, if it were implemented, I wouldn't expect it to have much trouble getting merged. Personally, I've argued every time this sort of solution has come up that it's incredibly ugly and tedious and that we should just do lazy imports if possible, because they would cleanly fix the compilation times without requiring such verbose workarounds. But of course, someone has to actually do the work of implementing lazy imports. - Jonathan M DavisOn Monday, 7 January 2019 at 21:50:20 UTC, Andrei Alexandrescu wrote:FYI: at the end of last year Eyal (Weka) and Andrei (and me a little bit) have been discussing lazy importing (full import) of symbols by the compiler. We hope to have a student work on this. Indeed I agree with you: the compiler could do (some of) this stuff, and because the rewards seem large it makes sense to indeed have the compiler do it.This is pretty awesome. Since the implementation would (initially at least) be private, the presence of "from" in documentation would beawkward. 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?
Jan 08 2019
On Tuesday, 8 January 2019 at 14:40:47 UTC, Johan Engelen wrote:On Tuesday, 8 January 2019 at 13:39:48 UTC, JN wrote:Make sure whoever works on it is aware of this: https://github.com/marler8997/dlangfeatures#lazy-imports To summarize, there's no way to make normal imports lazy (i.e. "import foo;"). However we can make the following lazy by default: 1. static imports (static import std.typecons;) 2. selective imports (import std.typecons: isBigEndian;) 3. aliased imports (import t = std.typecons;) I had a partial implementation for lazy imports, but Walter never reviewed my other pull requests so I never pushed it.On Monday, 7 January 2019 at 21:50:20 UTC, Andrei Alexandrescu wrote:FYI: at the end of last year Eyal (Weka) and Andrei (and me a little bit) have been discussing lazy importing (full import) of symbols by the compiler. We hope to have a student work on this. Indeed I agree with you: the compiler could do (some of) this stuff, and because the rewards seem large it makes sense to indeed have the compiler do it. -JohanThis 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?
Jan 09 2019
On Wednesday, 9 January 2019 at 22:39:58 UTC, Jonathan Marler wrote:Make sure whoever works on it is aware of this: https://github.com/marler8997/dlangfeatures#lazy-imports To summarize, there's no way to make normal imports lazy (i.e. "import foo;"). However we can make the following lazy by default: 1. static imports (static import std.typecons;) 2. selective imports (import std.typecons: isBigEndian;) 3. aliased imports (import t = std.typecons;) I had a partial implementation for lazy imports, but Walter never reviewed my other pull requests so I never pushed it.Maybe I'm missing something, but wouldn't it be possible to lazy import `import foo;` if the compiler checks lazily if a symbol isn't found in the current scope and only then tries to find it in one of the imports? Or would that be ineffective? Example: ---- import foo; // contains bar2 void bar1() { } bar1(); // in current scope bar2(); // not found, we have to search in the imports ----
Jan 09 2019
On Wed, 09 Jan 2019 22:59:59 +0000, Dgame wrote:Maybe I'm missing something, but wouldn't it be possible to lazy import `import foo;` if the compiler checks lazily if a symbol isn't found in the current scope and only then tries to find it in one of the imports? Or would that be ineffective?If you import two modules and both define functions named `write`, it is an error to use that function without somehow disambiguating. With every module import being lazy, it would only be an error if you had previously used symbols from both of those modules, and otherwise you'd get the function from whichever module has already been loaded.
Jan 09 2019
On Wednesday, 9 January 2019 at 23:14:09 UTC, Neia Neutuladh wrote:On Wed, 09 Jan 2019 22:59:59 +0000, Dgame wrote:That's right. Basically it boils down to this, as soon as you need to resolve the first symbol that isn't defined in the current module, you now have to load "ALL NORMAL IMPORTS" in the current scope; import foo, bar, baz; void func1() { } func1(); // don't need to import any modules func2(); // now you need to load all normal imports, foo, bar and baz. // even if you find func2 in the first module, you still have // to load them all because they could both define it and they // may either be ambiguous or one may have an overload that // matches better. plus, you have to load them all in order to // keep module order "invariant".Maybe I'm missing something, but wouldn't it be possible to lazy import `import foo;` if the compiler checks lazily if a symbol isn't found in the current scope and only then tries to find it in one of the imports? Or would that be ineffective?If you import two modules and both define functions named `write`, it is an error to use that function without somehow disambiguating. With every module import being lazy, it would only be an error if you had previously used symbols from both of those modules, and otherwise you'd get the function from whichever module has already been loaded.
Jan 09 2019
On Monday, 7 January 2019 at 21:50:20 UTC, Andrei Alexandrescu wrote:the presence of "from" in documentation would be awkward. So I suggest the glorious hack: alias std = from.std;Apart from compiler overhead, this seems to make `static import` redundant.
Jan 08 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: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? AndreiOn 1/4/19 8:11 AM, bauss 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("..."); from.some.other.package.func(1, 2, 3); and so on. TOn Thursday, 3 January 2019 at 23:54:42 UTC, SrMordred wrote:This is quite amazing.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("...");
Jan 05 2019