From c0a4f0719544ffb506b778c01b878615ce1c9f70 Mon Sep 17 00:00:00 2001 From: Marcelo Silva Nascimento Mancini Date: Tue, 20 Dec 2022 12:34:09 -0300 Subject: [PATCH 1/3] Mixin Template Intermediary Storage Want some feedback if something is a bit hazy or help if you can make it clearer --- DIPs/1NNN-HIP | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 DIPs/1NNN-HIP diff --git a/DIPs/1NNN-HIP b/DIPs/1NNN-HIP new file mode 100644 index 000000000..e9c364102 --- /dev/null +++ b/DIPs/1NNN-HIP @@ -0,0 +1,156 @@ +# Mixin Template Intermediary Storage + +| Field | Value | +|-----------------|-----------------------------------------------------------------| +| DIP: | (number/id -- assigned by DIP Manager) | +| Review Count: | 0 (edited by DIP Manager) | +| Author: | Marcelo Silva Nascimento Mancini (msnmancini@hotmail.com) | +| Implementation: | (links to implementation PR if any) | +| Status: | Draft | + +## Abstract + +Use intermediary variables inside mixin template without making it get included in +the code generation. + +## Contents +* [Rationale](#rationale) +* [Prior Work](#prior-work) +* [Description](#description) +* [Breaking Changes and Deprecations](#breaking-changes-and-deprecations) +* [Reference](#reference) +* [Copyright & License](#copyright--license) +* [Reviews](#reviews) + +## Rationale + +Using mixin template inside a class scope does not allow you to define intermediary data (as this intermediary data will be included in the class as members, which can cause unintended behavior). The common solution to that has been to generate a mixin template that executes a string mixin with a function, such as that: +```d +mixin template MyMixin(A) +{ + mixin(MyMixinImpl!A); +} + +``` +The problem with that approach is that it introduces a lot of mental friction from getting the syntax correctly inside a string, it makes compilation times slower as the possibility of using `format` or string append is really high. + +Another pattern that is also used for using variables inside `mixin template`, is creating a private template containg all variables necessary inside the mixin template: + +```d +private template Vars(A, string name) +{ + alias myMember = __traits(getMember, A, name); + enum _isConst = isConst!myMember; + enum _isRef = isRef!myMember; +} + +mixin template MyMixin(A) +{ + static foreach(mem; __traits(allMembers, A)) + { + static if(Vars!(A, mem)._isConst && Vars!(A, mem)._isRef){} + else static if(Vars!(A, mem)._isRef){} + else static if(Vars!(A, mem)._isConst){} + } +} +``` + +In summary, this is an attempt to make `mixin template` more capable. The following code errors out today with redefinition: + +```d +mixin template MyMixin(A) +{ + static foreach(mem; __traits(allMembers, A)) + { + alias myMember = __traits(getMember, A, mem); + enum _isConst = isConst!(myMember); + enum _isRef = isRef!(myMember); + + ///Now do what you need with those informations and combinations + static if(_isConst && _isRef){} + else static if(_isRef){} + else static if(_isConst){} + } +} +``` +As this code is not being able to compile, to run that code without using the string mixin or template trick, one would need to: +```d +static if(isConst!(__traits(getMember, A, mem)) && isRef!(__traits(getMember, A, mem))){} +else static if(isRef!(__traits(getMember, A, mem))){} +else static if(isConst!(__traits(getMember, A, mem))){} +``` + +This makes the code fairly unreadable and a lot more verbose. With the proposed solution, one could even reduce templates usage by using the following code: +```d +//non template execution for isConst +enum funcAttributes = __traits(getFunctionAttributes, myMember); +enum _isConst2 = funcAttributes.has("const"); +enum _isRef2 = funcAttributes.has("ref"); +``` + +The proposed solution for this problem is then the keywords `mixin delete`: +```d +mixin template MyMixin(A) +{ + static foreach(mem; __traits(allMembers, A)) + { + mixin delete { + alias myMember = __traits(getMember, A, mem); + enum funcAttributes = __traits(getFunctionAttributes, myMember); + enum _isConst = funcAttributes.has("const"); + enum _isRef = funcAttributes.has("ref"); + } + + ///Now do what you need with those informations and combinations + static if(_isConst && _isRef){} + else static if(_isRef){} + else static if(_isConst){} + } +} +``` + +## Prior Work +No prior work has been done on that. + +## Description + +All code inside `mixin delete` will need to be evaluated on compilation time, and will be usable inside `mixin template`. + +It must allow redefinition of variables or have other kind of mechanism for compatibility with `static foreach` (maybe generating an specific scope for mixin templates). + + + + +``` +Declaration: + FuncDeclaration + VarDeclarations + AliasDeclaration + AliasAssign + AggregateDeclaration + EnumDeclaration + ImportDeclaration + ConditionalDeclaration + StaticForeachDeclaration + StaticAssert ++ MixinDeleteDeclaration +``` + +``` ++MixinDeleteDeclaration: ++ mixin delete DeclarationBlock +``` + + + +## Breaking Changes and Deprecations +Breaking changes aren't anticipated as both `mixin` and `delete` keywords are reserved and the combination of them still doesn't exists. + +## Copyright & License +Copyright (c) 2022 by the D Language Foundation + +Licensed under [Creative Commons Zero 1.0](https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt) + +## Reviews +The DIP Manager will supplement this section with a summary of each review stage +of the DIP process beyond the Draft Review. From c1f054d1512612f325f9ecfc33ada70dcdd0f7d1 Mon Sep 17 00:00:00 2001 From: Marcelo Silva Nascimento Mancini Date: Tue, 20 Dec 2022 12:43:10 -0300 Subject: [PATCH 2/3] Rename 1NNN-HIP to 1NNN-HIP.md --- DIPs/{1NNN-HIP => 1NNN-HIP.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename DIPs/{1NNN-HIP => 1NNN-HIP.md} (100%) diff --git a/DIPs/1NNN-HIP b/DIPs/1NNN-HIP.md similarity index 100% rename from DIPs/1NNN-HIP rename to DIPs/1NNN-HIP.md From 0bfff0bcd6d4f6a59c1babe97f25d089aee6083a Mon Sep 17 00:00:00 2001 From: Marcelo Silva Nascimento Mancini Date: Tue, 20 Dec 2022 20:53:59 -0300 Subject: [PATCH 3/3] Update 1NNN-HIP.md Change from mixin delete to mixin private --- DIPs/1NNN-HIP.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/DIPs/1NNN-HIP.md b/DIPs/1NNN-HIP.md index e9c364102..84e73e2fb 100644 --- a/DIPs/1NNN-HIP.md +++ b/DIPs/1NNN-HIP.md @@ -88,13 +88,13 @@ enum _isConst2 = funcAttributes.has("const"); enum _isRef2 = funcAttributes.has("ref"); ``` -The proposed solution for this problem is then the keywords `mixin delete`: +The proposed solution for this problem is then the keywords `mixin private`: ```d mixin template MyMixin(A) { static foreach(mem; __traits(allMembers, A)) { - mixin delete { + mixin private { alias myMember = __traits(getMember, A, mem); enum funcAttributes = __traits(getFunctionAttributes, myMember); enum _isConst = funcAttributes.has("const"); @@ -114,7 +114,7 @@ No prior work has been done on that. ## Description -All code inside `mixin delete` will need to be evaluated on compilation time, and will be usable inside `mixin template`. +All code inside `mixin private` will need to be evaluated on compilation time, and will be usable inside `mixin template`. It must allow redefinition of variables or have other kind of mechanism for compatibility with `static foreach` (maybe generating an specific scope for mixin templates). @@ -133,18 +133,18 @@ Declaration: ConditionalDeclaration StaticForeachDeclaration StaticAssert -+ MixinDeleteDeclaration ++ MixinPrivateDeclaration ``` ``` -+MixinDeleteDeclaration: -+ mixin delete DeclarationBlock ++MixinPrivateDeclaration: ++ mixin private DeclarationBlock ``` ## Breaking Changes and Deprecations -Breaking changes aren't anticipated as both `mixin` and `delete` keywords are reserved and the combination of them still doesn't exists. +Breaking changes aren't anticipated as both `mixin` and `private` keywords are reserved and the combination of them still doesn't exists. ## Copyright & License Copyright (c) 2022 by the D Language Foundation