Re: void init of out variables
On Saturday, 19 August 2017 at 06:23:10 UTC, Igor Shirkalin wrote: On Saturday, 19 August 2017 at 06:20:28 UTC, Nicholas Wilson wrote: I have a function that takes a large matrix as an out parameter. Is there a way to do `=void` for an out parameter like there is for is for a plain declaration? enum M = 2600; void f() { float[M] mean = void; // works as expected, mean is left uninitialised } void g(out float[M][M] corr) // works but assigns twice { corr[] = float.init; // compiler inserted // assign to each value of corr } //Error: found ')' when expecting '.' following void void h(out float[M][M] corr = void) { } is there a way to not assign to out variables? Try 'ref' instead of 'out'. Hmm, I could, but ref doesn't signal intention like out does.
void init of out variables
I have a function that takes a large matrix as an out parameter. Is there a way to do `=void` for an out parameter like there is for is for a plain declaration? enum M = 2600; void f() { float[M] mean = void; // works as expected, mean is left uninitialised } void g(out float[M][M] corr) // works but assigns twice { corr[] = float.init; // compiler inserted // assign to each value of corr } //Error: found ')' when expecting '.' following void void h(out float[M][M] corr = void) { } is there a way to not assign to out variables?
Re: void init of out variables
On Saturday, 19 August 2017 at 06:20:28 UTC, Nicholas Wilson wrote: I have a function that takes a large matrix as an out parameter. Is there a way to do `=void` for an out parameter like there is for is for a plain declaration? enum M = 2600; void f() { float[M] mean = void; // works as expected, mean is left uninitialised } void g(out float[M][M] corr) // works but assigns twice { corr[] = float.init; // compiler inserted // assign to each value of corr } //Error: found ')' when expecting '.' following void void h(out float[M][M] corr = void) { } is there a way to not assign to out variables? Try 'ref' instead of 'out'.
Re: @safe(bool)
On 18 August 2017 at 02:32, bitwise via Digitalmars-d < digitalmars-d@puremagic.com> wrote: > This came to mind while working on a set of containers. > > @safety often comes with a performance cost. For example, any container > that wants to give out a range or iterator has to have a ref-counted or GC > allocted payload to ensure safety. In a high-performance context though, > the performance hit may be unacceptable. > This sounds like a job for `scope`. Eg, given a container, the function that returns the range/iterator should return a `scope` attributed range/iterator. This should insist that the lifetime of the range that is returned be no longer than the container that issued it. We've needed scope to address these issues for a very long time, and it finally arrived! I'm not sure how far it extends yet though, it's not well documented yet, and I haven't seen it get a lot of action. I'm not sure where the boundaries are.
Re: @safe(bool)
On Saturday, 19 August 2017 at 00:37:06 UTC, Nicholas Wilson wrote: Having to change the default attributes will be a rare occurrence (embedded (nothrow, nogc final) security critical (safe). My reading of that updated DIP is that you can only change the default attributes by hacking on DRuntime. If a project has a custom runtime, I would figure most people would mention it somewhere.
Re: @safe(bool)
On Friday, 18 August 2017 at 23:11:34 UTC, Jonathan M Davis wrote: On Friday, August 18, 2017 03:08:07 Nicholas Wilson via Digitalmars-d wrote: On Friday, 18 August 2017 at 01:43:42 UTC, Jonathan M Davis wrote: If you think that then I have clearly failed to express the DIP at all. It solves exactly that. I completely fail to see how it is a detriment to anything. The 'whole pile of other stuff' is reduced in further revisions to the DIP. IMHO, the problem that needs solving is that you can't negate attributes, making stuff like final: problematic. DIP 1012 goes way beyond that, and I don't think that that extra stuff is at all worth having, and I do think that it's detrimental. For instance, as it stands, it's relatively easy to figure out whether @safe has been explicitly applied. You can look on the function and look for @safe: or @safe {} which affects it. The same goes for other attributes. But as soon as you can do stuff like create new attributes that combine attributes, you lose that completely. Suddenly. you have to worry about whatever attributes someone came up on their own for their project which apply @safe or final or @nogc or whatever. You can no longer search or grep for an attribute like @safe to see whether it applies. As I have said before that is a deliberate feature of the DIP and not an incidental side product. Many people have requested such a feature. It also allows the DIP to solve the export problem: ```d version(MyLib_Build) enum MyLibExport = dynamicExport; else enum MyLibExport = dynamicImport; // Exported when building the shared object, // imported when linking against the shared object. @MyLibExport void foo(int x) { ... } ``` I get that you dislike that feature: yes you lose the ability to see it directly. grep still works (it might take more searches) and so does the documentation. Similarly, having it be possible to alter the default attributes globally is incredibly bad IMHO. Suddenly, whether your module compiles or not could depend on what settings someone used for the default attributes. That should not be controlled externally. It should be part of the module just like whether a function or variable is const or not is part of the module and not defined externally. IMHO, it makes no sense whatsoever to have something external control attributes any more than it makes sense to control the return types or constness of symbols externally. That should be part of the declarations/definitions of the symbols in question. That is a separable feature of the DIP, i.e. the DIP still functions without it, and if it truly so incredibly bad more people will say so. But, say you are developing for an embedded platform: you have no room for libunwind or exception table and can't use the gc. You see some library, libFoo, and you think "Aha! that does exactly what I need", then you think can I use it? is this library @nothrow @nogc? You could consult the documentation, but that doesn't tell you because there are a bunch of templates that dont have explicit attributes. You could try altering the examples to be @nothrow @nogc, or you could try to build the whole library as @nothrow @nogc and get error messages closer to the site of use. Yes it is niché, but it has its uses. [...] , but I don't at all agree that the rest of what DIP 1012 is trying to do is beneficial. It fixes export, allows grouping and manipulation of lists of attributes I honestly think that what DIP 1012 is trying to do beyond making it possible to negate attributes Yes, is going to make the language worse and code harder to maintain. No. Yes, it will enable some things that you can't do now, but for the most part, I don't think that those things should be enabled. I don't want to have to deal with folks complaining that my library doesn't work right, because they tried a different default for the attributes with it. Then that library is not for them. I don't want to have to worry about trying to get someone else's code to work because they assumed something about the default attributes that does not hold in my case. Then the library is not for you. Having to change the default attributes will be a rare occurrence (embedded (nothrow, nogc final) security critical (safe). I don't want to have to track down every custom attribute that someone came up with just to see whether they actually apply attributes like @safe or nothrow, just so that I can see whether those attributes apply. -vcg-ast, documentation. But really, how others do you go: I really need to know if that some function has a particular combination of attributes (serious)? I should be able to look at a module and see which attributes have been applied to the functions in that module without having to go searching elsewhere. IMHO, what needs to be solved with the built-in attributes, is the ability to negate the ones that don't have multiple
Re: @safe(bool)
On Friday, 18 August 2017 at 15:16:55 UTC, bitwise wrote: On Friday, 18 August 2017 at 01:43:42 UTC, Jonathan M Davis wrote: [...] - Jonathan M Davis Makes sense to me. The first question that comes to mind is if the extra generality provided by DIP 1012 is actually useful, let alone, worth breaking changes. It fixes the non-inverability. They become regular attributes instead of keywords. This has the effect of separating their definition from their usage allowing you to manipulate them like normal attributes, see https://github.com/dlang/DIPs/pull/89/ for the most recent revision. The only breaking changes are nothrow and pure get a leading '@'. They will go through a proper deprecation process and I will be very surprised if anything breaks. The new symbols added to core.attributes can use `@future` if need be to further reduce the likelihood of any breaking changes. The rationale section of the DIP only mentions negating attributes, which is easily accomplished with what I suggested. Unless that section is expanded with additional practical use cases, then it doesn't seem worth the trouble to me. The DIP mentions tagging a module declaration with default attributes. If the whole purpose of the DIP is to allow for negating attributes, why would you even need this change, when the DIP would effectively make it ok to put "@nogc: @safe: @etc:" at the top of the file? This is changed in pull #89. My suggestion does not cover "inferred" as discussed in the DIP, but that could be achieved by letting something like "@default" reset all attributes for a given symbol. How would you know what attributes were in effect before? I'll concede that DIP1012 makes more logical sense than the current state of things, but it seems like something that would be best achieved during a transition to a subsequent language version. It seems commonplace here, to discard suggestions based on their current viability, when it may be better to add them to a feature backlog that could be considered when talking about the possibility of a D3. Why? Breakage will be completely contained with transitional behaviour, i.e. the compiler will treat pure as @pure and nothrow as @nothrow. I can't think of any other facets that would warrant semi-indefinite delay.
Re: @safe(bool)
On Friday, August 18, 2017 03:08:07 Nicholas Wilson via Digitalmars-d wrote: > On Friday, 18 August 2017 at 01:43:42 UTC, Jonathan M Davis wrote: > If you think that then I have clearly failed to express the DIP > at all. > It solves exactly that. I completely fail to see how it is a > detriment to anything. > The 'whole pile of other stuff' is reduced in further revisions > to the DIP. IMHO, the problem that needs solving is that you can't negate attributes, making stuff like final: problematic. DIP 1012 goes way beyond that, and I don't think that that extra stuff is at all worth having, and I do think that it's detrimental. For instance, as it stands, it's relatively easy to figure out whether @safe has been explicitly applied. You can look on the function and look for @safe: or @safe {} which affects it. The same goes for other attributes. But as soon as you can do stuff like create new attributes that combine attributes, you lose that completely. Suddenly. you have to worry about whatever attributes someone came up on their own for their project which apply @safe or final or @nogc or whatever. You can no longer search or grep for an attribute like @safe to see whether it applies. Similarly, having it be possible to alter the default attributes globally is incredibly bad IMHO. Suddenly, whether your module compiles or not could depend on what settings someone used for the default attributes. That should not be controlled externally. It should be part of the module just like whether a function or variable is const or not is part of the module and not defined externally. IMHO, it makes no sense whatsoever to have something external control attributes any more than it makes sense to control the return types or constness of symbols externally. That should be part of the declarations/definitions of the symbols in question. And slapping something like @safe: at the top of the module solves the problem of applying attributes to an entire module right now just fine except for the fact that you can't negate attributes, meaning that aside from the few that have multiple states (namely, the @safety and access level attributes), you can't alter the attributes on specific functions if you mark the whole module with a particular attribute. So, we really should have a solution for negating attributes, but I don't at all agree that the rest of what DIP 1012 is trying to do is beneficial. I honestly think that what DIP 1012 is trying to do beyond making it possible to negate attributes is going to make the language worse and code harder to maintain. Yes, it will enable some things that you can't do now, but for the most part, I don't think that those things should be enabled. I don't want to have to deal with folks complaining that my library doesn't work right, because they tried a different default for the attributes with it. I don't want to have to worry about trying to get someone else's code to work because they assumed something about the default attributes that does not hold in my case. I don't want to have to track down every custom attribute that someone came up with just to see whether they actually apply attributes like @safe or nothrow, just so that I can see whether those attributes apply. I should be able to look at a module and see which attributes have been applied to the functions in that module without having to go searching elsewhere. IMHO, what needs to be solved with the built-in attributes, is the ability to negate the ones that don't have multiple states. With that, what we have now will work just fine. The rest is completely undesirable. - Jonathan M Davis
Re: Exception chaining and collectException
On 8/18/2017 2:09 AM, Don Clugston wrote: I invested quite a lot personally in implementing chained exceptions. But I agree with you. I was actually quite proud that I worked out the nasty corner cases during the initial implementation. As far as I can tell, problems with chained exceptions are not because of bugs and implementation issues, but because of problems with the concept itself. I think it's just a bit too clever. Thanks for the explanation. When I decided to support Dwarf exceptions, I spent a lot of time trying to match that behavior. We've all invested lots of time in things that didn't pay off. We mustn't get trapped by the sunk cost fallacy: https://en.wikipedia.org/wiki/Sunk_cost and I'm glad you're ok with that!
Re: Exception chaining and collectException
On 8/18/2017 5:07 AM, Steven Schveighoffer wrote: If we are to remove them, what happens when exceptions would normally chain? In C++, throwing an exception while unwinding is a fatal error. More information: https://stackoverflow.com/questions/130117/throwing-exceptions-out-of-a-destructor
Re: @safe(bool)
On 18.08.2017 17:16, bitwise wrote: On Friday, 18 August 2017 at 01:43:42 UTC, Jonathan M Davis wrote: [...] - Jonathan M Davis Makes sense to me. The first question that comes to mind is if the extra generality provided by DIP 1012 is actually useful, let alone, worth breaking changes. The rationale section of the DIP only mentions negating attributes, which is easily accomplished with what I suggested. Unless that section is expanded with additional practical use cases, then it doesn't seem worth the trouble to me. ... It's a vastly better design, because it does not try to overfit to a single use case. E.g. it allows abstracting over attributes. You can have an alias that contains sequences of attributes and then apply the summary: alias naughty = AliasSeq!(impure,system,throws,gc); alias nice = AliasSeq!(pure,safe,nothrow,nogc); @nice void foo(); @naughty void bar(); The DIP mentions tagging a module declaration with default attributes. If the whole purpose of the DIP is to allow for negating attributes, why would you even need this change, when the DIP would effectively make it ok to put "@nogc: @safe: @etc:" at the top of the file? My suggestion does not cover "inferred" as discussed in the DIP, but that could be achieved by letting something like "@default" reset all attributes for a given symbol. I'll concede that DIP1012 makes more logical sense than the current state of things, but it seems like something that would be best achieved during a transition to a subsequent language version. It seems commonplace here, to discard suggestions based on their current viability, when it may be better to add them to a feature backlog that could be considered when talking about the possibility of a D3. There are non-awkward backwards-compatible ways to implement DIP 1012.
Re: LDC, ARM: unnecessary default initialization
On Friday, 18 August 2017 at 12:09:04 UTC, kinke wrote: On Friday, 18 August 2017 at 09:42:25 UTC, Jack Applegame wrote: For some reason, the LDC default initializes the structure, even if initialization of all its members is specified as void. I believe that this is wrong. Afaik, this has been brought up multiple times already and is so by design. Every aggregate has an init symbol, omitting that (and accordingly the default initialization of all instances) by initializing each field with void doesn't work. The initialization isn't performed fieldwise, but is a bitcopy of T.init. You can skip initialization of specific instances though - `S s = void;` - but again not if `s` is a field of another aggregate. Sorry, I forgot some workaround code: void ResetHandler() { Foo foo = void; foo.__ctor(10); // or: std.conv.emplace(&foo, 10); }
Re: @safe(bool)
On Friday, 18 August 2017 at 01:43:42 UTC, Jonathan M Davis wrote: [...] - Jonathan M Davis Makes sense to me. The first question that comes to mind is if the extra generality provided by DIP 1012 is actually useful, let alone, worth breaking changes. The rationale section of the DIP only mentions negating attributes, which is easily accomplished with what I suggested. Unless that section is expanded with additional practical use cases, then it doesn't seem worth the trouble to me. The DIP mentions tagging a module declaration with default attributes. If the whole purpose of the DIP is to allow for negating attributes, why would you even need this change, when the DIP would effectively make it ok to put "@nogc: @safe: @etc:" at the top of the file? My suggestion does not cover "inferred" as discussed in the DIP, but that could be achieved by letting something like "@default" reset all attributes for a given symbol. I'll concede that DIP1012 makes more logical sense than the current state of things, but it seems like something that would be best achieved during a transition to a subsequent language version. It seems commonplace here, to discard suggestions based on their current viability, when it may be better to add them to a feature backlog that could be considered when talking about the possibility of a D3.
Re: Named multi-imports
On Friday, 18 August 2017 at 09:18:42 UTC, Timon Gehr wrote: Any downsides? ... - It introduces a new type that would not really be necessary. This is avoidable, at the cost of a little more verbosity: D newbie here: is there a non-negligible cost to creating a stateless struct type? Also, since the struct is private and only used for its aliases, if there a chance the compiler might elide those costs?
Re: Named multi-imports
On Friday, 18 August 2017 at 09:18:42 UTC, Timon Gehr wrote: --- module util; // ... template Imports(T...){ import std.string,std.algorithm; mixin([T].map!(x=>"public import "~x~";").join); // or, starting from DMD 2.076, you could use static foreach instead: // static foreach(x;T) mixin("public import "~x~";"); } // ... The static foreach is nice...doesn't depend on phobos.
dmd download record
Downloads from dlang.org, which doesn't include outside distro packages like Arch or FreeBSD, have now jumped an order of magnitude over the last five years: http://erdani.com/d/downloads.daily.png Congrats to all those who kept their head down grinding away on code, including the enlightening technical debates in this forum, as opposed to all the armchair strategists opining "What D really needs is..." but not submitting any pull requests (I partake in such strategizing too, but I have also contributed PRs to further the mobile effort, for example). Ldc has seen similar gains, look at the increased downloads over the last two years: http://www.somsubhra.com/github-release-stats/?username=ldc-developers&repository=ldc Here's to the next order of magnitude jump!
Re: LDC, ARM: unnecessary default initialization
On Friday, 18 August 2017 at 09:42:25 UTC, Jack Applegame wrote: For some reason, the LDC default initializes the structure, even if initialization of all its members is specified as void. I believe that this is wrong. Afaik, this has been brought up multiple times already and is so by design. Every aggregate has an init symbol, omitting that (and accordingly the default initialization of all instances) by initializing each field with void doesn't work. The initialization isn't performed fieldwise, but is a bitcopy of T.init. You can skip initialization of specific instances though - `S s = void;` - but again not if `s` is a field of another aggregate.
Re: Exception chaining and collectException
On Friday, 18 August 2017 at 03:31:38 UTC, Walter Bright wrote: Chained exceptions are a good idea, but are more or less a disaster: 1. No other language does chained exceptions 2. Attempting to hammer D chained exceptions into other language schemes (such as C++) makes for lots of unfun hours attempting to decode undocumented behavior in those other schemes 3. Makes D exceptions incompatible with other language exceptions and their infrastructure 4. Are incomprehensibly implemented (I defy anyone to explain how the test cases in the test suite are actually supposed to work) 5. Are more or less incompatible with non-GC memory allocation I'd like to remove them from D. I recommend *not* designing any program that requires them. If we are to remove them, what happens when exceptions would normally chain? -Steve
Re: Exception chaining and collectException
On Friday, 18 August 2017 at 09:09:47 UTC, Don Clugston wrote: Secondly, exception handling in windows is practically undocumented. Certainly it's not documented in a single place. When I began to implement it, I feared it might be impossible. There isn't any guarantee that exception chaining can actually be implemented on all platforms. I had actually tested the above on Windows with DMD 2.075.1 and got the expected behavior, not the buggy behavior. I invested quite a lot personally in implementing chained exceptions. But I agree with you. I was actually quite proud that I worked out the nasty corner cases during the initial implementation. As far as I can tell, problems with chained exceptions are not because of bugs and implementation issues, but because of problems with the concept itself. I think it's just a bit too clever. Do you mind pointing me in the direction of where chained exceptions are explained?
LDC, ARM: unnecessary default initialization
I explore the possibility of using D for bare metal ARM programming. For some reason, the LDC default initializes the structure, even if initialization of all its members is specified as void. I believe that this is wrong. test.d module test; import core.bitop : volatileStore; struct Foo { uint[64] m = void; // no default initialization this(uint a) { foreach(ref b; m) volatileStore(&b,a++); } } void ResetHandler() { auto foo = Foo(10); } $ldc2 -mtriple=thumb-none-linux-eabi -mcpu=cortex-m3 -c --betterC --boundscheck=off -relocation-model=static -O3 -vcolumns test.d test.o assembly <_D4test12ResetHandlerFZv>: 0: b510push{r4, lr} 2: b0c0sub sp, #256; 0x100 -+ 4: 466cmov r4, sp | default initialization 6: f44f 7180 mov.w r1, #256; 0x100 | a: 4620mov r0, r4 | WHY??? c: f7ff fffe bl 0 <__aeabi_memclr4> -+ 10: 2000movsr0, #0 12: f100 010a add.w r1, r0, #10 16: f844 1020 str.w r1, [r4, r0, lsl #2] 1a: 3001addsr0, #1 1c: 2949cmp r1, #73 ; 0x49 1e: d1f8bne.n 12 <_D4test12ResetHandlerFZv+0x12> 20: b040add sp, #256; 0x100 22: bd10pop {r4, pc} *
Re: Named multi-imports
On 18.08.2017 03:11, Johnson Jones wrote: private struct oo{ import std.stdio: writeln, write; import std.algorithm: filter, map; // … } void main(){ oo.write("result: "); oo.writeln(oo.map!(x=>x/2)(oo.filter!(x=>x%2==0)([1,2,3,4,5,6,10]))); } Wow, that might solve the problem! A little more verbose but it does combine everything. Any downsides? - It is more verbose. ;) - IMAO it shouldn't even work without 'public' on the imports. (So if someone decides to fix that it might break and become more verbose.) - It introduces a new type that would not really be necessary. This is avoidable, at the cost of a little more verbosity: private template Imports(){ public import std.stdio: writeln, write; public import std.algorithm: filter, map; } private alias oo = Imports!(); void main(){ oo.write("result: "); oo.writeln(oo.map!(x=>x/2)(oo.filter!(x=>x%2==0)([1,2,3,4,5,6,10]))); } The pattern can be abstracted into a utility template: --- module util; // ... template Imports(T...){ import std.string,std.algorithm; mixin([T].map!(x=>"public import "~x~";").join); // or, starting from DMD 2.076, you could use static foreach instead: // static foreach(x;T) mixin("public import "~x~";"); } // ... --- --- module main; import util: Imports; private alias oo = Imports!( `std.stdio: writeln, write`, `std.algorithm: filter, map` ); void main(){ oo.write("result: "); oo.writeln(oo.map!(x=>x/2)(oo.filter!(x=>x%2==0)([1,2,3,4,5,6,10]))); } --- Thanks. np.
Re: Exception chaining and collectException
On Friday, 18 August 2017 at 03:31:38 UTC, Walter Bright wrote: Chained exceptions are a good idea, but are more or less a disaster: 1. No other language does chained exceptions 2. Attempting to hammer D chained exceptions into other language schemes (such as C++) makes for lots of unfun hours attempting to decode undocumented behavior in those other schemes 3. Makes D exceptions incompatible with other language exceptions and their infrastructure 4. Are incomprehensibly implemented (I defy anyone to explain how the test cases in the test suite are actually supposed to work) Well, I wrote them, so I can explain that. The problem is that the idea that you can form a "chain" of exceptions turns out to be naive. What if a chained exception needs to get chained to another chained exception? And that then needs to be chained to another exception? It forms a tree! That's why the test cases are so complicated. So to a large extent, this extremely obscure corner case destroys the elegance of the concept. Secondly, exception handling in windows is practically undocumented. Certainly it's not documented in a single place. When I began to implement it, I feared it might be impossible. There isn't any guarantee that exception chaining can actually be implemented on all platforms. 5. Are more or less incompatible with non-GC memory allocation I'd like to remove them from D. I recommend *not* designing any program that requires them. I invested quite a lot personally in implementing chained exceptions. But I agree with you. I was actually quite proud that I worked out the nasty corner cases during the initial implementation. As far as I can tell, problems with chained exceptions are not because of bugs and implementation issues, but because of problems with the concept itself. I think it's just a bit too clever.
When using the -profile flag is it known behaviour that phobos unit tests fail?
When using the -profile flag is it known behaviour that phobos unit tests fail? (Ubuntu 16.04 - DMD64 D Compiler v2.071.0) For example, when following these steps I get a failed unit test: $ cd /usr/include/dmd/phobos/std/ $ rdmd -I/usr/include/dmd/phobos/std -I/usr/include/dmd/phobos/core -main -unittest -profile format.d
Re: Named multi-imports
On 18.08.2017 01:25, jmh530 wrote: On Thursday, 17 August 2017 at 21:49:38 UTC, Timon Gehr wrote: private struct oo{ import std.stdio: writeln, write; import std.algorithm: filter, map; // … } void main(){ oo.write("result: "); oo.writeln(oo.map!(x=>x/2)(oo.filter!(x=>x%2==0)([1,2,3,4,5,6,10]))); } Would not have thought to do that! Very cool. Quick follow up: is there a reason this why renamed selective imports don't work this way? I don't think there is. (I.e. I think it is indeed a bug.) As in the bug from the link below we discussed above https://issues.dlang.org/show_bug.cgi?id=17756 Re-writing the import like this seems like the perfect bug fix? It's one way to do it, but the compiler does not necessarily need to generate a new type. Note that unfortunately, renamed imports don't overload, so this would not work even with the fixed bug: import oo=std.stdio: writeln, write; import oo=std.algorithm: filter, map; // error: oo redefined void main(){ oo.write("result: "); oo.writeln(oo.map!(x=>x/2)(oo.filter!(x=>x%2==0)([1,2,3,4,5,6,10]))); } I think this is working as designed, but IMO they should just overload (using distinct overload sets so the semantics is similar to the case when using the struct), as should named mixins.