digitalmars.D - About structs and performant handling
- Namespace (74/74) Mar 09 2013 I would first like to apologize my bad English.
- Namespace (2/4) Mar 09 2013 Wrong link...
- bearophile (6/8) Mar 09 2013 Benchmarks on dpaste aren't very useful because I think no
- Namespace (20/26) Mar 09 2013 I used optimation switches:
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (27/40) Mar 09 2013 I have started working on the DConf presentation about copy and move
- Marco Leise (25/29) Mar 09 2013 Be aware of several things playing together here: L1 and L2
- Daniel Murphy (19/41) Mar 09 2013 Accessing a member of a stuct on the stack:
- Namespace (6/13) Mar 09 2013 And what if you want to pass it by value?
- Daniel Murphy (6/17) Mar 09 2013 You don't mark it with '&'.
- Namespace (4/10) Mar 09 2013 Oh, then I understood you wrong.
- Daniel Murphy (5/12) Mar 09 2013 If Jonathan made this claim in there, I must have missed it. Regardless...
- Namespace (2/7) Mar 10 2013 Like I said, read the thread. Or better, read all my threads on
- Daniel Murphy (3/9) Mar 10 2013 I have better things to do.
- Namespace (6/6) Mar 10 2013 Then just believe me. I have discussed the theme of 'auto ref' a
- deadalnix (5/12) Mar 10 2013 Auto ref will pass any lvalue by ref, even when it don't make any
- Daniel Murphy (4/14) Mar 11 2013 You're right, I was thinking about const auto ref. const auto ref could...
- Namespace (7/11) Mar 09 2013 If we have this we have still the problem that moving a big
- deadalnix (12/51) Mar 10 2013 Have you checked the assembly to see if a dereference actually
- Namespace (3/10) May 08 2013 Hey, could you please publish your slides of your DConf
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (22/33) May 08 2013 Yes, they are here:
- Namespace (3/3) May 08 2013 I was wondering where I can find your benchmarks as I read your
- Namespace (5/5) Mar 10 2013 Too bad, I had hoped for a little more discussion / feedback on
- Andrei Alexandrescu (4/8) Mar 10 2013 I can't hear or read "what's wrong with you" without remembering about
- deadalnix (14/21) Mar 10 2013 I don't think this is a good idea for several reasons.
- Namespace (4/10) Mar 10 2013 Haven't you then not the same problems with 'auto ref'?
- deadalnix (6/16) Mar 10 2013 As said in another post, I think auto ref suffer pretty much the
- Namespace (4/9) Mar 11 2013 The only problem with this is, that no one knows, if and when
- Namespace (13/16) Mar 11 2013 A better solution would be to require that a Parameter with '&'
- Zach the Mystic (9/26) Mar 11 2013 Your point reminds me of the fact that D has no "inline" or
- deadalnix (20/28) Mar 12 2013 Register keyword make no sense nowadays. Compiler can figure it
- Namespace (11/19) Mar 12 2013 I also think that we do not need 'inline' or 'register'.
- deadalnix (2/17) Mar 12 2013 You never gave any rationale reason on that.
- Namespace (8/9) Mar 12 2013 Because I just like to have the control over what is passed by
- deadalnix (3/12) Mar 12 2013 I'm sorry, but what you like is exactly the opposite of a
- Namespace (3/10) Mar 12 2013 I'll always like to disabuse. So why do you think this is not a
- deadalnix (38/49) Mar 12 2013 Let's consider the given example :
- Namespace (9/16) Mar 12 2013 I've misunderstood you, ignore my post above please.
- Marco Leise (11/14) Mar 12 2013 Not to forget that ever since we have Intel, AMD and different
- Namespace (6/9) Mar 10 2013 Yes, you're right. But I also said that the syntax does not
I would first like to apologize my bad English. I like to suggest a possible solution for the current rvalue ref problem (especially for structs). My suggestion is based on the idea of 'auto ref' and the proposal of deadalnix which was discussed here: http://forum.dlang.org/thread/funxviipfkdftmdfyrfk forum.dlang.org?page=1 Smaller structs are very performant if you move or copy them. This is more performant as to create them only to pass them by ref. But structs with a bigger size aren't that performant if you pass them as copy or move them (See also my small benchmark: http://dpaste.1azy.net/edit/b9624e01). So I like to suggest a new syntax for this behaviour. If you want that your function/method/whatever takes a struct as well as rvalue and lvalue, you declare this parameter with a '&' (Or whatever, the syntax doesn't matter at all. I like the '&' because I know it from C++ and many (C++) Newcomer will know what it means. Furthermore '&' is a lot shorter than eg. 'auto ref'). For example: [code] struct A { } void foo(A& a) { } [/code] The compiler will check by these kind of parameters if they are structs and if the size is proven greater as N (maybe 16 - 24) bit. If not, the '&' will be ignored. The function take in this cases normally lvalues as copy and moves rvalues. But if the struct size is greater than N the compiler changes the storage class of this parameter to ref. Example: If you have another struct B with the following structure (instead of the lightweight struct A): [code] struct B { public: int[100] ids; } [/code] the method 'foo' will be changed to: [code] void foo(ref B b) { } [/code] In this case lvalues are taken by ref and in case that a rvalue is used, a temporary variable is created and passed to the function (like C++ does). Or if you don't like temporary variables you could also use a wrapper, something like: [code] property ref T make(T, Args...)(Args args) { static if (args.length != 0) { static T result = void; T _temp = T(args); memcpy(&result, &_temp, T.sizeof); } else { static T result; } return result; } [/code] So the two possible kind of calls to foo would be: [code] B b; foo(b); [/code] and [code]foo(B());[/code] which is converted to: [code]foo(make!B);[/code] I see a lot of potential in this solution, because the compiler is taking care about gaining the most powerfull/performant code, it's simple (and simple is always good) AND it could solve the rvalue ref problem. And now you can behead me.
Mar 09 2013
(See also my small benchmark: http://dpaste.1azy.net/edit/b9624e01).Wrong link... I meant: http://dpaste.1azy.net/b9624e01
Mar 09 2013
Namespace:Wrong link... I meant: http://dpaste.1azy.net/b9624e01Benchmarks on dpaste aren't very useful because I think no optimization switches are used, and because the CPU is not under control, so other unknown tasks can steal some of its time. Bye, bearophile
Mar 09 2013
Benchmarks on dpaste aren't very useful because I think no optimization switches are used, and because the CPU is not under control, so other unknown tasks can steal some of its time. Bye, bearophileI used optimation switches: Application arguments: -O -release -noboundscheck But you're right, but what should I do? I could deliver you my results from my pc: [quote] Call b0 (B by ref). Duration: 259 total, 0.129500 average. Call b1 (B by move). Duration: 804 total, 0.402000 average. Call b2 (B by make). Duration: 364 total, 0.182000 average. Call b3 (B by copy). Duration: 943 total, 0.471500 average. Call b4 (B by manual move). Duration: 1101 total, 0.550500 average. Call b5 (A by move). Duration: 17 total, 0.008500 average. Call b6 (A by copy). Duration: 65 total, 0.032500 average. Call b7 (A by ref). Duration: 47 total, 0.023500 average. Call b8 (A by make). Duration: 54 total, 0.027000 average. [/quote] Also compiled with -O -release -noboundscheck on a Intel i5-2500k CPU with 3.30 GHz. But the script is there. So you could test by yourself. :)
Mar 09 2013
On 03/09/2013 12:19 PM, Namespace wrote:But structs with a bigger size aren't that performant if you pass them as copy or move them (See also my small benchmark:I have started working on the DConf presentation about copy and move semantics in D. I have done exactly the same type of tests and was surprised how faster pass-by-reference can be. To be fair, I have also accessed the members of the structs inside the function to see whether the pointer dereferencing in the by-ref case brought any cost. Apparently I have been ignorant in modern CPU designs because I was surprised to see that pointer dereferencing seemingly had no cost at all. My guess would be that the object is completely inside the processor's cache. Then I suspected dmd and made similar tests with gcc in the C language and have seen similar results. So yes, apparently by-ref is faster at least in some cases.For example: [code] struct A { } void foo(A& a) { } [/code] The compiler will check by these kind of parameters if they are structs and if the size is proven greater as N (maybe 16 - 24) bit. If not, the '&' will be ignored. The function take in this cases normally lvalues as copy and moves rvalues. But if the struct size is greater than N the compiler changes the storage class of this parameter to ref.I hope others with compiler knowledge will chime in here. I think the type of the parameter that is passed is intrinsic to how the function gets compiled. I think, for that to work, the compiler would have to compile two versions of the function, one taking by-value and the other taking by-ref. If what I said above is correct, then of course that wouldn't scale, e.g. we would need four separate compilations of the function if we had two parameters. Then there would be the issue of finding a naming scheme for these separate versions of the function so that the linker finds the right one. I am making up some names for the linker: foo_val_val(), foo_val_ref(), foo_ref_val(), foo_ref_ref(). Others, please correct me if I am wrong above. :) Ali
Mar 09 2013
Am Sat, 09 Mar 2013 15:07:49 -0800 schrieb Ali =C3=87ehreli <acehreli yahoo.com>:Apparently I have been ignorant in modern CPU designs=20 because I was surprised to see that pointer dereferencing seemingly had=20 no cost at all. My guess would be that the object is completely inside=20 the processor's cache.Be aware of several things playing together here: L1 and L2 cache as well as prefetching and order of the data in memory. If you create a few KiB of data and run it through a test its all in the L1 cache and blazing fast. If you have a game and load a matrix struct from somewhere scattered in memory you'll see the massive access penalty. The modern prefetchers in CPUs keep track of a N streams of forward or backward serial memory accesses. So they work perfectly for iterating an array for example. The work in the "background" and use free memory bandwidth to load data from RAM to CPU caches before you actually need it. This hides the memory delay that has become increasingly larger in the past years. It is so important that many don't optimize for CPU cycles anymore but instead for memory access and cache locality: * http://en.wikipedia.org/wiki/Judy_array * http://research.scee.net/files/presentations/gcapaustralia09/Pitfalls_of_= Object_Oriented_Programming_GCAP_09.pdf Its easy to underestimate the effects until you benchmark with some several MiB large random memory access patterns and see how you get close to a 100 times slow down. --=20 Marco
Mar 09 2013
"Ali Çehreli" <acehreli yahoo.com> wrote in message news:khgfc6$1m9i$1 digitalmars.com...To be fair, I have also accessed the members of the structs inside the function to see whether the pointer dereferencing in the by-ref case brought any cost. Apparently I have been ignorant in modern CPU designs because I was surprised to see that pointer dereferencing seemingly had no cost at all. My guess would be that the object is completely inside the processor's cache.Accessing a member of a stuct on the stack: mov EDX, dword ptr [ESP+stackoffset+memberoffset] Accessing a member of a struct on the heap: (assume pointer to struct is in EAX) mov EDX, dword ptr [EAX+memberoffset] A lot of the time the heap pointer will be in a register already. Stack memory will almost always be in the caches, and so will recently used heap memory. If you want to measure the cost of loading the heap pointer then dereferencing, you might want to mark all the registers as used so the compiler is forced to reload. eg with asm {}A better way to do with would be to change (or extend) the abi, so that structs over a certain size are always passed by reference with this parameter type. Then you only need one version of the function. We could use auto ref for this.For example: [code] struct A { } void foo(A& a) { } [/code] The compiler will check by these kind of parameters if they are structs and if the size is proven greater as N (maybe 16 - 24) bit. If not, the '&' will be ignored. The function take in this cases normally lvalues as copy and moves rvalues. But if the struct size is greater than N the compiler changes the storage class of this parameter to ref.I hope others with compiler knowledge will chime in here. I think the type of the parameter that is passed is intrinsic to how the function gets compiled. I think, for that to work, the compiler would have to compile two versions of the function, one taking by-value and the other taking by-ref.
Mar 09 2013
A better way to do with would be to change (or extend) the abi, so that structs over a certain size are always passed by reference with this parameter type.And what if you want to pass it by value? I am a opponent of such automatic and uncontrollable compiler intervention. Better to manually identify something to be on the safe side.Then you only need one version of the function. We could use auto ref for this.'auto ref' will probably never work for non-template functions, as Jonathan said some time ago.
Mar 09 2013
"Namespace" <rswhite4 googlemail.com> wrote in message news:qmznbrplexqrdqahgaus forum.dlang.org...You don't mark it with '&'.A better way to do with would be to change (or extend) the abi, so that structs over a certain size are always passed by reference with this parameter type.And what if you want to pass it by value?I am a opponent of such automatic and uncontrollable compiler intervention. Better to manually identify something to be on the safe side.Then I don't understand the point. If it doesn't need to be automatic, you can just do it in your own code (use ref/not ref)That is not my understanding.Then you only need one version of the function. We could use auto ref for this.'auto ref' will probably never work for non-template functions, as Jonathan said some time ago.
Mar 09 2013
You don't mark it with '&'.Oh, then I understood you wrong. I thought you meant that the compiler for each struct parameters (whether marked or not) just automatically perform such changes.Read my thread 'auto ref - again'.That is not my understanding.Then you only need one version of the function. We could use auto ref for this.'auto ref' will probably never work for non-template functions, as Jonathan said some time ago.
Mar 09 2013
"Namespace" <rswhite4 googlemail.com> wrote in message news:aucfrmomyneucfykpmap forum.dlang.org...If Jonathan made this claim in there, I must have missed it. Regardless, there is an open pull request that implements auto ref, which has not been accepted or rejected yet.Read my thread 'auto ref - again'.That is not my understanding.Then you only need one version of the function. We could use auto ref for this.'auto ref' will probably never work for non-template functions, as Jonathan said some time ago.
Mar 09 2013
If Jonathan made this claim in there, I must have missed it. Regardless, there is an open pull request that implements auto ref, which has not been accepted or rejected yet.Like I said, read the thread. Or better, read all my threads on this topic.
Mar 10 2013
"Namespace" <rswhite4 googlemail.com> wrote in message news:hlsfrzwwmwtepuidxgrt forum.dlang.org...I have better things to do.If Jonathan made this claim in there, I must have missed it. Regardless, there is an open pull request that implements auto ref, which has not been accepted or rejected yet.Like I said, read the thread. Or better, read all my threads on this topic.
Mar 10 2013
Then just believe me. I have discussed the theme of 'auto ref' a lot of times. And I would be still happy if 'auto ref' would also work for non-template functions. But I just think my idea still goes a step further. After all, it takes into account the problem of moving large structs.
Mar 10 2013
On Sunday, 10 March 2013 at 02:17:36 UTC, Daniel Murphy wrote:A better way to do with would be to change (or extend) the abi, so that structs over a certain size are always passed by reference with this parameter type. Then you only need one version of the function. We could use auto ref for this.Auto ref will pass any lvalue by ref, even when it don't make any sense (small structs). It also expose different semantic according if an revalue or an lvalue is passed. It has roughly the same issues as this thread's proposal.
Mar 10 2013
"deadalnix" <deadalnix gmail.com> wrote in message news:libldszmvkzcezcfkktx forum.dlang.org...On Sunday, 10 March 2013 at 02:17:36 UTC, Daniel Murphy wrote:You're right, I was thinking about const auto ref. const auto ref could pass values however it felt, and nobody would ever know.A better way to do with would be to change (or extend) the abi, so that structs over a certain size are always passed by reference with this parameter type. Then you only need one version of the function. We could use auto ref for this.Auto ref will pass any lvalue by ref, even when it don't make any sense (small structs). It also expose different semantic according if an revalue or an lvalue is passed. It has roughly the same issues as this thread's proposal.
Mar 11 2013
I think the type of the parameter that is passed is intrinsic to how the function gets compiled. I think, for that to work, the compiler would have to compile two versions of the function, one taking by-value and the other taking by-ref.If we have this we have still the problem that moving a big struct is slow. My 'make' is a lot faster. Therefore I suggested this new behaviour instead of the old deliberations about 'auto ref'. And I thought, because it is probable, that 'auto ref' will never work for non-template function, my Idea would be a nice alternative. :)
Mar 09 2013
On Saturday, 9 March 2013 at 23:07:50 UTC, Ali Çehreli wrote:On 03/09/2013 12:19 PM, Namespace wrote:Have you checked the assembly to see if a dereference actually happened ? This should be performant anyway, because the stack frame is likely to be in cache.But structs with a bigger size aren't that performant if youpass themas copy or move them (See also my small benchmark:I have started working on the DConf presentation about copy and move semantics in D. I have done exactly the same type of tests and was surprised how faster pass-by-reference can be. To be fair, I have also accessed the members of the structs inside the function to see whether the pointer dereferencing in the by-ref case brought any cost. Apparently I have been ignorant in modern CPU designs because I was surprised to see that pointer dereferencing seemingly had no cost at all. My guess would be that the object is completely inside the processor's cache.Then I suspected dmd and made similar tests with gcc in the C language and have seen similar results. So yes, apparently by-ref is faster at least in some cases.Indeed, if the struct is big enough or the copy expensive !I don't think so. Many function's parameters aren't electible to such mecanism (or it'd be a bug) and many type don't gain to be passed by ref (small struct, like slice, delegate, a very large amount in fact).The compiler will check by these kind of parameters if theyare structsand if the size is proven greater as N (maybe 16 - 24) bit.If not, the'&' will be ignored. The function take in this cases normallylvalues ascopy and moves rvalues. But if the struct size is greater than N the compiler changesthestorage class of this parameter to ref.I hope others with compiler knowledge will chime in here. I think the type of the parameter that is passed is intrinsic to how the function gets compiled. I think, for that to work, the compiler would have to compile two versions of the function, one taking by-value and the other taking by-ref. If what I said above is correct, then of course that wouldn't scale, e.g. we would need four separate compilations of the function if we had two parameters.Then there would be the issue of finding a naming scheme for these separate versions of the function so that the linker finds the right one. I am making up some names for the linker: foo_val_val(), foo_val_ref(), foo_ref_val(), foo_ref_ref().Yes, mangling must be affected, but I don't think this is that bad.
Mar 10 2013
On Saturday, 9 March 2013 at 23:07:50 UTC, Ali Çehreli wrote:On 03/09/2013 12:19 PM, Namespace wrote:Hey, could you please publish your slides of your DConf presentation? :)But structs with a bigger size aren't that performant if youpass themas copy or move them (See also my small benchmark:I have started working on the DConf presentation about copy and move semantics in D. I have done exactly the same type of tests and was surprised how faster pass-by-reference can be.
May 08 2013
On 05/08/2013 05:57 AM, Namespace wrote:On Saturday, 9 March 2013 at 23:07:50 UTC, Ali Çehreli wrote:Yes, they are here: http://acehreli.org/AliCehreli_copy_move_D.pdf But I see that you have been after some test results between by-copy vs. by-ref parameters. I have decided not to include them in the presentation for various reasons: not enough presentation time, not trusting my synthetic tests enough to be sure that I was covering all aspects of the behaviors of modern cpu architectures, etc. I can say that by-value was almost always slower in my little test. However, as others have been saying, by-ref can be slower if a lot of the members of the struct are accessed through that reference, effectively defeating the CPU caches. For me to see that by-ref was slower, I had to define huge structs, put them in huge arrays, and touch all of the members of random elements of that array: // s1 and s2 are random elements of huge arrays void foo(ref const(S) s1, ref const(S) s2) { // use all members of s1 and s2 } Only then by-ref was slower than by-value. Let me build more trust in my test before opening it to discussion on the forums. AliOn 03/09/2013 12:19 PM, Namespace wrote:Hey, could you please publish your slides of your DConf presentation? :)But structs with a bigger size aren't that performant if youpass themas copy or move them (See also my small benchmark:I have started working on the DConf presentation about copy and move semantics in D. I have done exactly the same type of tests and was surprised how faster pass-by-reference can be.
May 08 2013
I was wondering where I can find your benchmarks as I read your slides. Now it has become clearer. I'm looking forward to reading your benchmarks and assessments. :)
May 08 2013
Too bad, I had hoped for a little more discussion / feedback on this topic. Is it a good idea or a bad one. It is complete nonsense or has it been a right to exist, etc. What's wrong with you guys?
Mar 10 2013
On 3/10/13 2:57 PM, Namespace wrote:Too bad, I had hoped for a little more discussion / feedback on this topic. Is it a good idea or a bad one. It is complete nonsense or has it been a right to exist, etc. What's wrong with you guys?I can't hear or read "what's wrong with you" without remembering about https://www.youtube.com/watch?v=nV7u1VBhWCE... Andrei
Mar 10 2013
On Saturday, 9 March 2013 at 20:19:10 UTC, Namespace wrote:So I like to suggest a new syntax for this behaviour. If you want that your function/method/whatever takes a struct as well as rvalue and lvalue, you declare this parameter with a '&' (Or whatever, the syntax doesn't matter at all. I like the '&' because I know it from C++ and many (C++) Newcomer will know what it means. Furthermore '&' is a lot shorter than eg. 'auto ref').I don't think this is a good idea for several reasons. First, it introduce a new syntax, which is always a concern. It add language complexity, and it likely to not be used everywhere it should. Second, the default behavior must be the most beneficial one. Simply because it will be the most used, and we don't want good code to be crippled with many addition here and there. Providing a default suboptimal behavior (here performancewise). Finally, I think this behavior is very dangerous. Pass by reference and value have very different. With that construct, you'll never know which one you get as the compiler decide ! If the compiler and not the programmer decide what the program does (not implementation wise, but semantically), we have a problem.
Mar 10 2013
Finally, I think this behavior is very dangerous. Pass by reference and value have very different. With that construct, you'll never know which one you get as the compiler decide ! If the compiler and not the programmer decide what the program does (not implementation wise, but semantically), we have a problem.Haven't you then not the same problems with 'auto ref'? But you could prohibit any manipulation of a '&' parameter. Eg. you could make him 'scope' by default (if 'scope' will work someday).
Mar 10 2013
On Sunday, 10 March 2013 at 19:27:01 UTC, Namespace wrote:As said in another post, I think auto ref suffer pretty much the same problem, but it is less problematic as you can't see the result on rvalues anyway, so the compiler cannot really screw you. It has the inconvenience of taking by ref many thing that would benefit from pass by value.Finally, I think this behavior is very dangerous. Pass by reference and value have very different. With that construct, you'll never know which one you get as the compiler decide ! If the compiler and not the programmer decide what the program does (not implementation wise, but semantically), we have a problem.Haven't you then not the same problems with 'auto ref'? But you could prohibit any manipulation of a '&' parameter. Eg. you could make him 'scope' by default (if 'scope' will work someday).
Mar 10 2013
As said in another post, I think auto ref suffer pretty much the same problem, but it is less problematic as you can't see the result on rvalues anyway, so the compiler cannot really screw you. It has the inconvenience of taking by ref many thing that would benefit from pass by value.The only problem with this is, that no one knows, if and when 'auto ref' will be implemented for non-templates. I still hope to an official statement, but I think this is unfortunately unrealistic.
Mar 11 2013
On Sunday, 10 March 2013 at 19:27:01 UTC, Namespace wrote:But you could prohibit any manipulation of a '&' parameter. Eg. you could make him 'scope' by default (if 'scope' will work someday).A better solution would be to require that a Parameter with '&' need 'const scope' as storage class. So the syntax would be: void foo(in A& a) { In my opinion, there is then no reason to worry about whether it is an lvalue or an rvalue. It cannot be changed or referenced. This: void foo(A& a) { without const scope would cause an error like : "Error: '&' requires const scope." AFAIK the syntax 'in ref' was suggested by Kenji but was rejected for some reasons.
Mar 11 2013
On Monday, 11 March 2013 at 10:55:50 UTC, Namespace wrote:On Sunday, 10 March 2013 at 19:27:01 UTC, Namespace wrote:Your point reminds me of the fact that D has no "inline" or "register" keywords. You probably couldn't pick better experts than the D compiler builders for deciding whether or not those two keywords are necessary. I guess there's not a clear solution to this question, or it would have been settled a while ago. Maybe it should be called the "performance ref" issue, to distinguish it from other ref issues, " safe ref", "auto ref", etc.But you could prohibit any manipulation of a '&' parameter. Eg. you could make him 'scope' by default (if 'scope' will work someday).A better solution would be to require that a Parameter with '&' need 'const scope' as storage class. So the syntax would be: void foo(in A& a) { In my opinion, there is then no reason to worry about whether it is an lvalue or an rvalue. It cannot be changed or referenced. This: void foo(A& a) { without const scope would cause an error like : "Error: '&' requires const scope." AFAIK the syntax 'in ref' was suggested by Kenji but was rejected for some reasons.
Mar 11 2013
On Tuesday, 12 March 2013 at 06:36:32 UTC, Zach the Mystic wrote:Your point reminds me of the fact that D has no "inline" or "register" keywords. You probably couldn't pick better experts than the D compiler builders for deciding whether or not those two keywords are necessary. I guess there's not a clear solution to this question, or it would have been settled a while ago. Maybe it should be called the "performance ref" issue, to distinguish it from other ref issues, " safe ref", "auto ref", etc.Register keyword make no sense nowadays. Compiler can figure it out way better than you. You could forget about some register keyword and slow down you program for nothing. You could use some register keyword and create bug because you got your aliasing wrong. And all that would require a huge amount of work and clutter the codebase. register keyword is a relic from the past, even in C. inlining is more subtle. In the general case, compiler get it better than humans, however, it is a much harder problem than register, so being able to hint the compiler may be useful. However, the usage of this is limited to very specific use cases. I don't see any reason to not allow the compiler to do so and create copy on a per needed basis, by optimizing pass-by value into pass-by-reference when it can prove it doesn't change the semantic (see my thread on the topic, but modify it to apply the restriction to anything possibly aliased). For the same reason as inline and register, I do think the default behavior is to let the compiler choose what is the bast as long as it doesn't change the final behavior.
Mar 12 2013
I also think that we do not need 'inline' or 'register'. Nowadays, compilers can really assess the situation much better than we do.I don't see any reason to not allow the compiler to do so and create copy on a per needed basis, by optimizing pass-by value into pass-by-reference when it can prove it doesn't change the semantic (see my thread on the topic, but modify it to apply the restriction to anything possibly aliased). For the same reason as inline and register, I do think the default behavior is to let the compiler choose what is the bast as long as it doesn't change the final behavior.I know your thread, I was one of the most active there. And I liked the idea, provided such parameters must be still manually denoted. And if such parameters are also denoted with 'in' or 'const scope', I see no way that they could be manipulated. I was hoping that Andrei and Walter could say something about the topic. I like to see something like that and it would solve the 'rvalue ref' problem also.
Mar 12 2013
On Tuesday, 12 March 2013 at 08:21:50 UTC, Namespace wrote:I also think that we do not need 'inline' or 'register'. Nowadays, compilers can really assess the situation much better than we do.You never gave any rationale reason on that.I don't see any reason to not allow the compiler to do so and create copy on a per needed basis, by optimizing pass-by value into pass-by-reference when it can prove it doesn't change the semantic (see my thread on the topic, but modify it to apply the restriction to anything possibly aliased). For the same reason as inline and register, I do think the default behavior is to let the compiler choose what is the bast as long as it doesn't change the final behavior.I know your thread, I was one of the most active there. And I liked the idea, provided such parameters must be still manually denoted.
Mar 12 2013
You never gave any rationale reason on that.Because I just like to have the control over what is passed by ref and what by value. Maybe I want that a bigger struct is passed by value. As long as I must denote parameters accordingly, in order that the compiler decide instead of me, this is no problem. But if you have no control, because the compiler will decide for you, it would not be possible. I'm considering a small example until evening.
Mar 12 2013
On Tuesday, 12 March 2013 at 09:24:11 UTC, Namespace wrote:I'm sorry, but what you like is exactly the opposite of a rational example.You never gave any rationale reason on that.Because I just like to have the control over what is passed by ref and what by value.Maybe I want that a bigger struct is passed by value. As long as I must denote parameters accordingly, in order that the compiler decide instead of me, this is no problem. But if you have no control, because the compiler will decide for you, it would not be possible. I'm considering a small example until evening.
Mar 12 2013
On Tuesday, 12 March 2013 at 09:38:19 UTC, deadalnix wrote:On Tuesday, 12 March 2013 at 09:24:11 UTC, Namespace wrote:I'll always like to disabuse. So why do you think this is not a rational example? And what would a rational example for you?I'm sorry, but what you like is exactly the opposite of a rational example.You never gave any rationale reason on that.Because I just like to have the control over what is passed by ref and what by value.
Mar 12 2013
On Tuesday, 12 March 2013 at 11:24:43 UTC, Namespace wrote:On Tuesday, 12 March 2013 at 09:38:19 UTC, deadalnix wrote:Let's consider the given example : struct Foo { uint i; this(this) { writeln("foo"); } } void bar(Foo f) { writeln("bar"); } uint main() { Foo f; f.i = 42; bar(f); return f.i, } You think you pass by value ? In fact, if you let the optimizer do its job, you don't even have a function call. Thing gets rewriten this way : uint main() { writeln("foo"); writeln("bar"); return 42; } You have no function call and no pass by value anymore. In fact, the only thing the current definition garantee it that you have the side effect of the postblit (ie, memory allocation, etc . . .), but nothing is said about having an actual function call or a pass by value. If you think you control the code that way, you are living a delusional world, because the compiler rewrite everything under you. You are asking to keep that illusion in place by asking for an explicit syntax to allow the optimization to take place. And note that this is very good thing as the code generated is much faster and the code much cleaner. If you had to specify optimisations, you'd get them wrong, you'd forget them, your code would be less reliable, slower and less readable.On Tuesday, 12 March 2013 at 09:24:11 UTC, Namespace wrote:I'll always like to disabuse. So why do you think this is not a rational example? And what would a rational example for you?I'm sorry, but what you like is exactly the opposite of a rational example.You never gave any rationale reason on that.Because I just like to have the control over what is passed by ref and what by value.
Mar 12 2013
On Tuesday, 12 March 2013 at 09:38:19 UTC, deadalnix wrote:On Tuesday, 12 March 2013 at 09:24:11 UTC, Namespace wrote:I've misunderstood you, ignore my post above please. Well, I said "I like [...]" but I meant "It's important to controll what is passed by ref and what by value.". But I haven't yet an example for this. So maybe you're right. Whatever, our first concern should be to stimulate thinking of this and to call attention of Walter and/or Andrei. Then we can still debated whether such parameters should be labeled as such, or not.I'm sorry, but what you like is exactly the opposite of a rational example.You never gave any rationale reason on that.Because I just like to have the control over what is passed by ref and what by value.
Mar 12 2013
On Tuesday, 12 March 2013 at 11:58:26 UTC, Namespace wrote:On Tuesday, 12 March 2013 at 09:38:19 UTC, deadalnix wrote:Here is what I think. How the thing is actually passed don't matter. What does matter is that the semantic is know : ie that the program will behave in a known way. As a consequence, if the compiler choose to pass by ref instead of passing by value as an optimization, it must do so only if it can prove that the resulting code will do the same thing.On Tuesday, 12 March 2013 at 09:24:11 UTC, Namespace wrote:I've misunderstood you, ignore my post above please. Well, I said "I like [...]" but I meant "It's important to controll what is passed by ref and what by value.". But I haven't yet an example for this. So maybe you're right. Whatever, our first concern should be to stimulate thinking of this and to call attention of Walter and/or Andrei. Then we can still debated whether such parameters should be labeled as such, or not.I'm sorry, but what you like is exactly the opposite of a rational example.You never gave any rationale reason on that.Because I just like to have the control over what is passed by ref and what by value.
Mar 12 2013
Here is what I think. How the thing is actually passed don't matter. What does matter is that the semantic is know : ie that the program will behave in a known way.I agree.As a consequence, if the compiler choose to pass by ref instead of passing by value as an optimization, it must do so only if it can prove that the resulting code will do the same thing.And how could it be proved? IMO with const (not mutable) scope (no escaping). What are your thoughts?
Mar 12 2013
On Tuesday, 12 March 2013 at 15:19:14 UTC, Namespace wrote:To repeat myself : The caller is free to call the ref version of the function unless (rules evaluate in order) : - The argument is an rvalue (in such case, no postblit is executed as well). - The argument is shared. - The argument's postblit in not pure (weakly). The callee must create a local copy if (this is not verbatim from previous post as it has limitations as been pointed pointed) : - Mutate the struct or anything that *may* alias/be transitively reached through the struct. - Pass by ref/address taken to a non const/non weakly pure function (including method call) of the struct or anything that *may* alias/be transitively reached through the struct. It does guarantee that visible result will be the same.As a consequence, if the compiler choose to pass by ref instead of passing by value as an optimization, it must do so only if it can prove that the resulting code will do the same thing.And how could it be proved? IMO with const (not mutable) scope (no escaping). What are your thoughts?
Mar 12 2013
To repeat myself : The caller is free to call the ref version of the function unless (rules evaluate in order) : - The argument is an rvalue (in such case, no postblit is executed as well). - The argument is shared. - The argument's postblit in not pure (weakly). The callee must create a local copy if (this is not verbatim from previous post as it has limitations as been pointed pointed) : - Mutate the struct or anything that *may* alias/be transitively reached through the struct. - Pass by ref/address taken to a non const/non weakly pure function (including method call) of the struct or anything that *may* alias/be transitively reached through the struct. It does guarantee that visible result will be the same.Because I do not understand everything (due to my bad English) I would be glad to see one or maybe more examples where the compiler (according to your rules) change pass by value into pass by reference, and where not. And the problem remains that we have to get the attention of Walter or Andrei.
Mar 12 2013
One option, that I could think of why one should mark such parameters, would be that the compiler can then point out what is missing so that it would be potentially possible. Example: void foo (A a) { Because 'a' is not const and not scope, the compiler could not change the behavior from passing by value to passing by reference. But when the parameter is marked accordingly: void foo (A& a) { You get an error / warning: "Parameters with '&' require const scope." Whether 'A' ultimately is really big enough to make it worthwhile to have it passed by ref is irrelevant for that.
Mar 12 2013
Am Tue, 12 Mar 2013 09:21:49 +0100 schrieb "Namespace" <rswhite4 googlemail.com>:I also think that we do not need 'inline' or 'register'. Nowadays, compilers can really assess the situation much better than we do.Not to forget that ever since we have Intel, AMD and different generations of complex CPUs (branch prediction, prefetching, ...) in coexistence all the work you do to optimize on your CPU (which improves over the compiler generated code) might slow down the next CPU. Maybe embedded developers disagree with my x86 centristic view, though :) -- Marco
Mar 12 2013
First, it introduce a new syntax, which is always a concern. It add language complexity, and it likely to not be used everywhere it should.Yes, you're right. But I also said that the syntax does not matter. My intention was to stimulate thinking about the real issue. Even if "auto ref" will work someday for non-templates (we really need an official statement about that), then even small structs will be passed by ref. And that's still very ugly.
Mar 10 2013