-
-
Notifications
You must be signed in to change notification settings - Fork 422
Conversation
Is this intended to be a replacement or an addition to your DIP? |
@JackStouffer looks like a solid candidate for replacement. |
In this trivial example I am reading massive speedups. This looks promising. But, the real test would converting a whole module from Phobos to this style, with no top level imports, and seeing the results. import std.datetime;
import std.traits;
void func(T)(SysTime a, T value) if (isIntegral!T)
{
import std.stdio : writeln;
writeln(a, value);
}
void main() {}
VS template from(string moduleName)
{
mixin("import from = " ~ moduleName ~ ";");
}
void func(T)(from!"std.datetime".SysTime a, T value) if (from!"std.traits".isIntegral!T)
{
import std.stdio : writeln;
writeln(a, value);
}
void main() {}
|
I tried and failed to convert std.file to this format to get some performance numbers. Got some really odd and unhelpful error messages from the compiler when I removed std.range.primitives and std.traits from the top level. |
@JackStouffer: yes, that was my experience as well, as I thoroughly documented in the initial discussion around DIP1005. It didn't produce much of an impression - it seems one must try it in order to understand the difficulties :). |
If I may suggest a name change, I would use |
How would this work with UFCS? For some stuff, that doesn't necessarily matter much, but for something like the range primitives, it could matter a lot. For instance, if you have a function that accepts a range, and the template constraint uses the range primitives, the range primitives need to have been imported for the constraint to work with dynamic arrays. If the imports are just associated with the function as a whole like DIP 1005 does, then that's not a problem, but if you're using UFCS, then you need to import the symbol separately from using it, and this solution would appear to require that the import be associated with a symbol - or at least that's how all of the examples are using it. Also, what happens with this if you're using multiple symbols from the same module inside of the parameters and/or template constraints? Do you have to use |
@deadalnix I don't know, I think I like |
|
+1 for with (from!"std.datetime") Just observe how much better this reads: with (Module!"std.datetime") While cute-looking solutions have a habit of stroking one's ego, perpetuating the idea of programming as magic is precisely not what well-designed language artefacts are supposed to do. |
One matter is that the invocation solves to a module alias, not a type name, so by convention it needs to start with a lowecase letter, not uppercase. (I fail to grok the argument with cuteness, egos being stroked, and magic.) |
@klickverbot void popFrontN(R)(R range, size_t n) if (from!"std.range.primitives").isInputRange!R); or void popFrontN(R)(R range, size_t n) if (Module!"std.range.primitives").isInputRange!R); etc. Both seem plausible (the naming convention is worth considering though). |
Depends on your convention. ;) I would assert that modules, just like ambiguous generic templates should be referred to as in uppercase. I suppose it depends on where you put the default – value-like or type-like.
Both do seem plausible. I'm just pointing out that the artefact admits more uses than just the |
Phobos uses |
The advantage to |
As long as this is the case, it seems like it would be a very bad idea to promote an idiom like this. |
Hmm, interesting. This also applies to local imports where the local import is inside a template, and the template is not instantiated by the module that defines the template. However, the import should be added to the list of the module that instantiates it. Unfortunately, it does not. https://issues.dlang.org/show_bug.cgi?id=17181 |
Has anyone considered leaving away imports for fully qualified names? |
@MartinNowak Problem is it's unclear whether |
Would "non-locality" (e.g. having a preceding @andralex: If we want to go for an auto-import feature, it seems like local scope disambiguation itself wouldn't be the biggest issue. We could simply anchor the automatic feature to the root of the lookup tree (i.e. "one above module-level imports"), with the same shadowing properties as today. The second problem – disambiguating between (Edit for readability.) |
disambiguating between [a module].[b.c symbol] and [a.b module].[c symbol seems to be the harder one to solve in a universal fashion
@andralex , @klickverbot @MartinNowak
My suggestion in
http://forum.dlang.org/thread/[email protected]
(syntax sugar: std.path::buildPath instead of from!"std.path".buildPath)
proposes a solution for this:
it would be: a.b::c.d
meaning Module!"a.b".c.d (ie, lazy static import of module a.b followed by
symbol access c.d)
|
Maybe just try from longest to shortest module, taking the first match? It seems the more important question is how important static imports in function/template parameters are. Modularity was named as a prime motivation. We could have a look at those after the current lookup changes are transitioned and the planned import refactorings are through (late H1, early H2). |
I would very much like to see lazy imports happen. I'm already getting sick of using local and selective imports all over the place instead of just importing modules. It does have the advantage of making it clear where stuff comes from and minimizing which parts of the module see the imports, but it's just plain tedious and adds maintenance overhead. As I understand it, having fully lazy imports would largely make local and selective imports unnecessary from a performance perspective, and as such, I would probably stop doing much with selective and local imports, because they're just so tedious. And going with |
@jmdavis, I agree that it's too tedious to use local, selective imports everywhere, but I think the endgame is a process where you just stick a bunch of non-selective, module-scope imports up top while you're writing your code, ie the way almost all D code is written now, and then when done, run a tool over it to properly scope all the imports and make them selective. Doing it by hand is never going to scale, we need a tool. Building such an import tool, by integrating the ddmd frontend with libdparse, is now third in my D queue, with the top two about to be cleared away. Lazy imports may take away the performance need for such a tool, but better documentation is well worth doing it anyway. |
IMHO, if we expect a tool to be used in order for your code to follow best practices in D, then we've screwed up. I have no problem with someone writing a tool that they think will make their life easier, but as I understand it, choices were made with D's features in order to avoid the need for tooling beyond the compiler - particularly with regards to boilerplate code. And I, for one, don't want to have to be running extra tools on my code. It should be reasonable to just write it and have it follow best practices. And if having fully lazy imports largely gets rid of the need for scoped and selective imports, I'm very much in favor of having fully lazy imports as the solution. scoped and selective imports result in far too much boilerplate code and IMHO are a maintenance problem. They do provide some value in terms of encapsulating dependencies, but I just don't think that they're worth that. |
I disagree. There is a certain class of source transformations that should be automated: for example, I can just write my code formatted fairly sloppily and then run |
I have no problem with someone running a tool to do source transformations if they want to. I have a problem with us deciding that something is best practice which basically requires that we run a tool. You should be able to reasonably write good, clean code that follows best practices without needing to run additional tools if you don't want to. And scoped and selective imports border on needing a tool because of how tedious they are to write and maintain.
I don't understand this. The verbosity and the fact that they require a fair bit of upkeep in comparison to simply importing the module you need at the top is precisely the problem. You end up with a lot of extra lines in your code and a decent amount of extra effort - particularly when selective imports are added into the mix. If anything, selective imports make it exponentially worse. And if we had fully lazy imports, then the performance benefits of using them would be negated, making it far more reasonable to just import modules at the top and be done with it. |
You can, nobody is stopping you from perfectly formatting your code and scoping all your imports from the first line you write. However, you can also just write your D code formatted sloppily and with top-level imports and then have the The key here is that nobody is making D coders perfectly format their code (like python's indentation rules) and scope all their imports. It is up to you if you want the benefits those provide and we'll be able to say, "Here are some tools to make your life easier."
The extra lines have a purpose, they document where exactly the symbols are coming from, which lazy imports do not. I believe that is worth it, perhaps you do not. As for extra effort, there's none required other than running the tool, but you seem to be against that. I agree that scoped, selective imports will not be used much if we require everybody to insert them by hand, but I'm not against tools to do that for us, if we choose to scope our imports. |
I'm not against the tool existing either. The problem is that increasingly, it seems to be that it's considered best practice to use scoped and selective imports, which is a pain to do by hand. So, if you want to follow "best practice," then it starts looking like a tool is needed in order for that to be manageable, which runs contrary to the idea that you should not need a tool for boilerplate in D (much as anyone is free to use a tool if they want one). One of the reasons that scoped and selective imports are pushed for the way that they are is because of the performance benefits, and if we had fully lazy imports like Walter has talked about doing, then that benefit of scoped and selective imports would be negated. Folks could still use them if they wanted, and they could even use a tool to manage them if they wanted to, but I think that there would be a much weaker argument that it was best practice to use them. And after trying to use them for a while and getting sick of all of the extra, tedious work required to maintain them, I would very much like to see us not need them and not be in a position where it's tooted as best practice and that you should change your code to use them if you're not. It seems to me that fully lazy imports solve the primary problem while requiring a lot less work on the part of D programmers in general. IMHO, it would be a huge win. |
I was thinking we need more time to decide which approach to choose. |
That's unfortunate. Was hoping for a scheme that minimizes the files opened and imported - the moment we get to |
Yes, that may impact performance. This logic is needed for ambiguities like |
Thanks for your pull request, @andralex! Bugzilla referencesYour PR doesn't reference any Bugzilla issue. If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog. Testing this PR locallyIf you don't have a local development environment setup, you can use Digger to test this PR: dub run digger -- build "master + druntime#1756" |
import_
for inline importsimported
for inline imports
Thanks for your pull request, @andralex! Bugzilla referencesYour PR doesn't reference any Bugzilla issue. If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog. Testing this PR locallyIf you don't have a local development environment setup, you can use Digger to test this PR: dub run digger -- build "master + druntime#1756" |
Doesn't this get further discussion? 👀
|
@ljmf00 Given that the |
Fair point 👍 |
@andralex Please rebase this to fix the tester issues. |
Thanks for your pull request, @andralex! Bugzilla referencesYour PR doesn't reference any Bugzilla issue. If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog. Testing this PR locallyIf you don't have a local development environment setup, you can use Digger to test this PR: dub run digger -- build "master + druntime#1756" |
Are we supposed to make use of this template in as many places (in druntime phobos) as possible now? If so, I wonder if that is gonna lead to a non-insignificant overhead in space when doing, for instance, |
I'd say cautiously at first, with an eye on impact on build times and quality of generated documentation. |
[I'm mostly worried about aesthetics - from that POV, I'd prefer not seeing this used at all. ;)] |
Why (again) where the following non-templated-bloated alternatives turned down: foo(T)(T x)
if (isIntegral!T)
with(import std.traits) , foo(T)(T x)
if ((import std.traits).isIntegral!T) , and foo(T)(T x)
if ((import std.traits : isIntegral)!T) turned down? To site @andralex, all of these would "simply remove a limitation in the language". |
Trying a library solution now does not mean we cannot add a new language feature later, if the library solution proves inadequate. |
Indeed. Moreover, a semi-automatic search--and-replace of Btw, when you say inadequate what comes to your mind, @pbackus? |
No description provided.