D style - member functions
Consider: ``` struct S1 { int A; int B; int foo() { return(A+B); } } struct S2 { int A; int B; } int fnAddS2(S2 X) { return (X.A + X.B); } void main() { import std.stdio : writeln; S1 Var1 = S1(1, 2); writeln("Total Var1 = ", Var1.foo()); S2 Var2 = S2(1, 2); writeln("Total Var2 = ", fnAddS2(Var2)); return; } ``` Of the two ways shown of producing the total from the same underlying structure, which is the better style? Further, do we care about the situation where there are many variables of type 'S', which presumably means the function code generated from S1 gets duplicated many times, but not so with S2?
Re: D style - member functions
On Wed, Apr 26, 2023 at 06:24:08PM +, DLearner via Digitalmars-d-learn wrote: > Consider: > ``` > struct S1 { >int A; >int B; >int foo() { > return(A+B); >} > } > > struct S2 { >int A; >int B; > } > int fnAddS2(S2 X) { >return (X.A + X.B); > } > > void main() { >import std.stdio : writeln; > >S1 Var1 = S1(1, 2); >writeln("Total Var1 = ", Var1.foo()); > >S2 Var2 = S2(1, 2); >writeln("Total Var2 = ", fnAddS2(Var2)); > >return; > } > ``` > > Of the two ways shown of producing the total from the same underlying > structure, which is the better style? Either way works, it doesn't really matter. The slight difference is that the member function is preferred when resolving a symbol, so if there's a module-level function called `foo` that takes S1 as a parameter, the member function would be called instead. > Further, do we care about the situation where there are many variables > of type 'S', which presumably means the function code generated from > S1 gets duplicated many times, but not so with S2? This is false. Member functions are only instantiated once in the entire program, not with every instance of S. (Template functions may be instantiated more than once, but that's still only once per combination of template arguments, not once per instance of the enclosing type.) T -- MAS = Mana Ada Sistem?
Re: D style - member functions
On Wednesday, 26 April 2023 at 18:24:08 UTC, DLearner wrote: Consider: ``` struct S1 { int A; int B; int foo() { return(A+B); } } struct S2 { int A; int B; } int fnAddS2(S2 X) { return (X.A + X.B); } There are scenarios that won't let you use the second form, e.g. putting your struct under the `with()` statement: ```d with (S1) { auto sum = foo(); // Works correctly } with (S2) { auto sum = foo(); // Error: function foo(S s) is not callable using argument types () } ``` In this case, the first option will be better. But there are no real "best practices" defined AFAIK. However, the second form let you generalize the pattern by using template declaration: ```d int fnAdd(T)(T v) { return (v.A + v.B); // Doesn't matter what type is this if it has both members A and B } s1.fnAdd(); s2.fnAdd(); ```
Re: D style - member functions
On Wednesday, 26 April 2023 at 18:24:08 UTC, DLearner wrote: Consider: ``` struct S1 { int A; int B; int foo() { return(A+B); } } struct S2 { int A; int B; } int fnAddS2(S2 X) { return (X.A + X.B); } void main() { import std.stdio : writeln; S1 Var1 = S1(1, 2); writeln("Total Var1 = ", Var1.foo()); S2 Var2 = S2(1, 2); writeln("Total Var2 = ", fnAddS2(Var2)); return; } ``` Of the two ways shown of producing the total from the same underlying structure, which is the better style? To make both version really equivalent you should rather write int fnAddS2(ref S2 X) { return (X.A + X.B); } the `this` for the member functions is a reference as obviously you want to eventually mutate the members and not their copy. What happened in your `fnAddS2` is that the whole stuff was blitted and mutation of the members would have no effect on the argument used in the call. Further, do we care about the situation where there are many variables of type 'S', which presumably means the function code generated from S1 gets duplicated many times, but not so with S2? Your presumption is wrong. The code generated for a function is not regenerated per instance. One version is enough to handle all the instances as the instance is itself a parameter of the function. What is happening for `foo()`, i.e the member function, is that there is an hidden parameter. Depending on the language the way the hidden argument is read might be slightly different but you really should consider that struct S1 { int A; int B; int foo() { return(A+B); } } is like struct S1 { int A; int B; static int foo(ref S1 that) { return(that.A+that.B); } } or struct S1 { int A; int B; } int foo(ref S1 that) { return(that.A+that.B); } One problem of the hidden parameter is that for example int foo(const ref S1 that) { return(that.A+that.B); } cannot be expressed (at first glance)... how to qualify `const` something that is hidden ? It's actually possible using a member function attribute: struct S1 { int A; int B; int foo() const /*const is for the hidden parameter*/ { return(A+B); } }
quick question, probably of little importance...
I just need an even/odd functionality. Don't think D has a built-in operator. // Found this C code online. int isEven(int num) { return !(num & 1); } // found this in std.functional.unaryFun alias isEven = unaryFun!("(a & 1) == 0"); assert(isEven(2) && !isEven(1)); If interested just in speed, is either one faster?
Re: quick question, probably of little importance...
Don't forget ``num % 2 == 0``. None should matter, pretty much all production compilers within the last 30 years should recognize all forms of this and do the right thing.
Re: quick question, probably of little importance...
On Wednesday, 26 April 2023 at 23:02:07 UTC, Richard (Rikki) Andrew Cattermole wrote: Don't forget ``num % 2 == 0``. None should matter, pretty much all production compilers within the last 30 years should recognize all forms of this and do the right thing. Thanks. Fastest reply ever! And I believe across the world? I suppose my examples required overhead of a function call. So maybe num % 2 == 0 is fastest?
Re: quick question, probably of little importance...
On Wed, Apr 26, 2023 at 11:07:39PM +, WhatMeWorry via Digitalmars-d-learn wrote: > On Wednesday, 26 April 2023 at 23:02:07 UTC, Richard (Rikki) Andrew > Cattermole wrote: > > Don't forget ``num % 2 == 0``. > > > > None should matter, pretty much all production compilers within the > > last 30 years should recognize all forms of this and do the right > > thing. > > Thanks. Fastest reply ever! And I believe across the world? I > suppose my examples required overhead of a function call. So maybe num > % 2 == 0 is fastest? If performance matters, you'd be using an optimizing compiler. And unless you're hiding your function implementation behind a .di, almost all optimizing compilers would inline it, so you shouldn't even be able to tell the difference. T -- Without outlines, life would be pointless.
Re: quick question, probably of little importance...
On 27/04/2023 11:07 AM, WhatMeWorry wrote: On Wednesday, 26 April 2023 at 23:02:07 UTC, Richard (Rikki) Andrew Cattermole wrote: Don't forget ``num % 2 == 0``. None should matter, pretty much all production compilers within the last 30 years should recognize all forms of this and do the right thing. Thanks. Fastest reply ever! And I believe across the world? I suppose my examples required overhead of a function call. So maybe num % 2 == 0 is fastest? Indeed, all the way from New Zealand. I wouldn't bother timing this. A compiler will rewrite it and emit whatever instructions it thinks is best for a given cpu target that you select. This is one of those things that was solved 30 years ago :)