digitalmars.D - Call site 'ref'
- =?ISO-8859-1?Q?Alex_R=F8nne_Petersen?= (23/23) Jan 15 2012 Hi,
- Johnatan Frakes (3/3) Jan 15 2012 You are, lazy, sir, and your programming license should be revoked.
- Peter Alexander (7/10) Jan 15 2012 This has nothing to do with laziness. It's an error-detection mechanism,...
- =?ISO-8859-1?Q?Alex_R=F8nne_Petersen?= (5/17) Jan 15 2012 That sounds reasonable to me. Maybe make it a compiler option like
- Stewart Gordon (9/11) Jan 17 2012 Maybe phase it in in this sequence:
- =?ISO-8859-1?Q?Alex_R=F8nne_Petersen?= (8/11) Jan 15 2012 By your logic, we should remove all compiler checks that help avoid
- F i L (3/7) Jan 15 2012 Good idea, but it should be optional. On by default maybe, but
- =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= (5/12) Jan 15 2012 Absolutely. It would break way too much code if it was made an error. I
- dsimcha (4/25) Jan 15 2012 This would break UFCS severely. The following would no longer work:
- Peter Alexander (3/36) Jan 15 2012 Unless it was ignored for UFCS, which is reasonable, since foo.bar()
- =?ISO-8859-1?Q?Alex_R=F8nne_Petersen?= (4/42) Jan 15 2012 Agreed.
- Robert Jacques (12/33) Jan 15 2012 In no particular order:
- Peter Alexander (14/47) Jan 15 2012 A fair point, but:
- Tobias Pankrath (2/4) Jan 15 2012 Which is true for me. Every single one of my reference parameters is con...
- bearophile (5/10) Jan 15 2012 (What you do is also required by the Google C++ style guide.)
- Alvaro (4/8) Jan 15 2012 swap(ref a, ref b); // ??
- Robert Jacques (13/65) Jan 15 2012 So, you're proposing to "fix" the language instead of using a better dev...
- bearophile (5/7) Jan 15 2012 C# is meant to be used with a modern IDE, yet it requires "ref" and "out...
- Mehrdad (3/24) Jan 15 2012 I suggested this a while ago but people acted as though I was talking
- Nick Sabalausky (7/28) Jan 15 2012 Yes, this is one of the few things I always thought C# got right and D g...
- Timon Gehr (2/38) Jan 15 2012
- Timon Gehr (24/45) Jan 15 2012 Odd. I always thought the fact that std.utf.decode modifies the second
- Peter Alexander (7/12) Jan 15 2012 Actually, that would be very dangerous. const ref does not have the
- Timon Gehr (5/17) Jan 15 2012 Who on earth wants to change an int parameter from by value to by const
- Timon Gehr (2/24) Jan 15 2012 (Even the claim that there is no danger of it being modified is plain wr...
- Peter Alexander (12/30) Jan 15 2012 Are you sure about struct literals binding to const ref? I can't find
- Timon Gehr (3/36) Jan 15 2012 I agree, but banning it would be an arbitrary and pointless restriction.
- Jonathan M Davis (21/22) Jan 15 2012 Yeah. I don't understand that. I've argued about it with Walter before.
- Peter Alexander (8/12) Jan 15 2012 In C++, struct literals are rvalues. C++ just has a special rule that
- Timon Gehr (6/20) Jan 15 2012 In C++, a struct literal can be on the lhs of an expression (because of
- Andrei Alexandrescu (3/12) Jan 15 2012 That's a bad rule that we shouldn't copy.
- Timon Gehr (3/16) Jan 15 2012 What do you think is an optimal rule regarding struct
- Andrei Alexandrescu (3/21) Jan 15 2012 auto ref
- Timon Gehr (2/25) Jan 15 2012 But that only works for templates?
- Andrei Alexandrescu (4/33) Jan 18 2012 For non-templates, if it's important to distinguish between lvalues and
- Timon Gehr (4/38) Jan 18 2012 Currently 'auto ref' gives a compile error if used in a non-templated
- Andrei Alexandrescu (5/13) Jan 18 2012 I meant two overloads that don't use auto ref:
- Peter Alexander (2/14) Jan 15 2012 I agree.
- Timon Gehr (8/61) Jan 15 2012 Oh, and furthermore it would give rise to abominations such as:
- Jonathan M Davis (38/39) Jan 15 2012 This was discussed before, and I'm still completely against it. It _onl=
- Mail Mantis (11/34) Jan 15 2012 is
- =?ISO-8859-1?Q?Alex_R=F8nne_Petersen?= (5/43) Jan 15 2012 You may remember what the function does, but forget that it mutates an
- Timon Gehr (2/53) Jan 16 2012 This statement is self-contradictory.
- Mehrdad (6/12) Jan 16 2012 "If the documentation explains it, the code doesn't need to."
- Mail Mantis (6/10) Jan 16 2012 Maybe - if you have access to function's source text. But we were
Hi, I don't know how many times I've made the mistake of passing a local variable to a function which takes a 'ref' parameter. Suddenly, local variables/fields are just mutating out of nowhere, because it's not at all obvious that a function you're calling is taking a 'ref' parameter. This is particularly true for std.utf.decode(). Yes, I realize I could look at the function declaration. Yes, I could read the docs too. But that doesn't prevent me from forgetting that a function takes a 'ref' parameter, and then doing the mistake again. The damage is done, and the time is wasted. I think D should allow 'ref' on call sites to prevent these mistakes. For example: string str = ...; size_t pos; auto chr = std.utf.decode(str, ref pos); Now it's much more obvious that the parameter is passed by reference and is going to be mutated. Ideally, this would not be optional, but rather *required*, but I realize that such a change would break a *lot* of code, so that's probably not a good idea. Thoughts? -- - Alex
Jan 15 2012
You are, lazy, sir, and your programming license should be revoked. By that logic we should dull all knives because somebody might get hurt. My 2c.
Jan 15 2012
On 15/01/12 1:56 PM, Johnatan Frakes wrote:You are, lazy, sir, and your programming license should be revoked. By that logic we should dull all knives because somebody might get hurt. My 2c.This has nothing to do with laziness. It's an error-detection mechanism, just like many other language features (e.g. override, const, immutable, shared, ...). I agree with requiring ref at the call site in principle, although it would be too much of a breaking change to introduce now. Perhaps allow it, and issue a warning if not used?
Jan 15 2012
On 15-01-2012 15:12, Peter Alexander wrote:On 15/01/12 1:56 PM, Johnatan Frakes wrote:That sounds reasonable to me. Maybe make it a compiler option like -property though? -callsiteref? Something like that. -- - AlexYou are, lazy, sir, and your programming license should be revoked. By that logic we should dull all knives because somebody might get hurt. My 2c.This has nothing to do with laziness. It's an error-detection mechanism, just like many other language features (e.g. override, const, immutable, shared, ...). I agree with requiring ref at the call site in principle, although it would be too much of a breaking change to introduce now. Perhaps allow it, and issue a warning if not used?
Jan 15 2012
On 15/01/2012 14:12, Peter Alexander wrote: <snip>I agree with requiring ref at the call site in principle, although it would be too much of a breaking change to introduce now. Perhaps allow it, and issue a warning if not used?Maybe phase it in in this sequence: 1. Allow ref/out at call site. 2. Add a warning for if ref/out at call site is omitted. 3. Deprecate omitting ref/out at call site. 4. Require ref/out at call site. 5. Allow overloading of functions based on parameter storage class, as much as makes sense. Stewart.
Jan 17 2012
On 15-01-2012 14:56, Johnatan Frakes wrote:You are, lazy, sir, and your programming license should be revoked. By that logic we should dull all knives because somebody might get hurt. My 2c.By your logic, we should remove all compiler checks that help avoid typical mistakes. This is not about one extreme or another; it's about striking the right balance. This is not the first time this issue has been brought up, and there's a reason for that. -- - Alex
Jan 15 2012
Alex Rønne Petersen wrote:Ideally, this would not be optional, but rather *required*, but I realize that such a change would break a *lot* of code, so that's probably not a good idea. Thoughts?Good idea, but it should be optional. On by default maybe, but optional.
Jan 15 2012
On 15-01-2012 15:05, F i L wrote:Alex Rønne Petersen wrote:Absolutely. It would break way too much code if it was made an error. I think Peter Alexander's suggestion would work nicely. -- - AlexIdeally, this would not be optional, but rather *required*, but I realize that such a change would break a *lot* of code, so that's probably not a good idea. Thoughts?Good idea, but it should be optional. On by default maybe, but optional.
Jan 15 2012
On 1/15/2012 8:36 AM, Alex Rønne Petersen wrote:Hi, I don't know how many times I've made the mistake of passing a local variable to a function which takes a 'ref' parameter. Suddenly, local variables/fields are just mutating out of nowhere, because it's not at all obvious that a function you're calling is taking a 'ref' parameter. This is particularly true for std.utf.decode(). Yes, I realize I could look at the function declaration. Yes, I could read the docs too. But that doesn't prevent me from forgetting that a function takes a 'ref' parameter, and then doing the mistake again. The damage is done, and the time is wasted. I think D should allow 'ref' on call sites to prevent these mistakes. For example: string str = ...; size_t pos; auto chr = std.utf.decode(str, ref pos); Now it's much more obvious that the parameter is passed by reference and is going to be mutated. Ideally, this would not be optional, but rather *required*, but I realize that such a change would break a *lot* of code, so that's probably not a good idea. Thoughts?This would break UFCS severely. The following would no longer work: auto arr = [1, 2, 3, 4, 5]; arr.popFront(); // popFront takes arr by ref
Jan 15 2012
On 15/01/12 3:19 PM, dsimcha wrote:On 1/15/2012 8:36 AM, Alex Rønne Petersen wrote:Unless it was ignored for UFCS, which is reasonable, since foo.bar() looks like it could modify foo whereas bar(foo) doesn't in general.Hi, I don't know how many times I've made the mistake of passing a local variable to a function which takes a 'ref' parameter. Suddenly, local variables/fields are just mutating out of nowhere, because it's not at all obvious that a function you're calling is taking a 'ref' parameter. This is particularly true for std.utf.decode(). Yes, I realize I could look at the function declaration. Yes, I could read the docs too. But that doesn't prevent me from forgetting that a function takes a 'ref' parameter, and then doing the mistake again. The damage is done, and the time is wasted. I think D should allow 'ref' on call sites to prevent these mistakes. For example: string str = ...; size_t pos; auto chr = std.utf.decode(str, ref pos); Now it's much more obvious that the parameter is passed by reference and is going to be mutated. Ideally, this would not be optional, but rather *required*, but I realize that such a change would break a *lot* of code, so that's probably not a good idea. Thoughts?This would break UFCS severely. The following would no longer work: auto arr = [1, 2, 3, 4, 5]; arr.popFront(); // popFront takes arr by ref
Jan 15 2012
On 15-01-2012 16:47, Peter Alexander wrote:On 15/01/12 3:19 PM, dsimcha wrote:Agreed. -- - AlexOn 1/15/2012 8:36 AM, Alex Rønne Petersen wrote:Unless it was ignored for UFCS, which is reasonable, since foo.bar() looks like it could modify foo whereas bar(foo) doesn't in general.Hi, I don't know how many times I've made the mistake of passing a local variable to a function which takes a 'ref' parameter. Suddenly, local variables/fields are just mutating out of nowhere, because it's not at all obvious that a function you're calling is taking a 'ref' parameter. This is particularly true for std.utf.decode(). Yes, I realize I could look at the function declaration. Yes, I could read the docs too. But that doesn't prevent me from forgetting that a function takes a 'ref' parameter, and then doing the mistake again. The damage is done, and the time is wasted. I think D should allow 'ref' on call sites to prevent these mistakes. For example: string str = ...; size_t pos; auto chr = std.utf.decode(str, ref pos); Now it's much more obvious that the parameter is passed by reference and is going to be mutated. Ideally, this would not be optional, but rather *required*, but I realize that such a change would break a *lot* of code, so that's probably not a good idea. Thoughts?This would break UFCS severely. The following would no longer work: auto arr = [1, 2, 3, 4, 5]; arr.popFront(); // popFront takes arr by ref
Jan 15 2012
On Sun, 15 Jan 2012 07:36:53 -0600, Alex Rønne Petersen <xtzgzorex gmail.com> wrote:Hi, I don't know how many times I've made the mistake of passing a local variable to a function which takes a 'ref' parameter. Suddenly, local variables/fields are just mutating out of nowhere, because it's not at all obvious that a function you're calling is taking a 'ref' parameter. This is particularly true for std.utf.decode(). Yes, I realize I could look at the function declaration. Yes, I could read the docs too. But that doesn't prevent me from forgetting that a function takes a 'ref' parameter, and then doing the mistake again. The damage is done, and the time is wasted. I think D should allow 'ref' on call sites to prevent these mistakes. For example: string str = ...; size_t pos; auto chr = std.utf.decode(str, ref pos); Now it's much more obvious that the parameter is passed by reference and is going to be mutated. Ideally, this would not be optional, but rather *required*, but I realize that such a change would break a *lot* of code, so that's probably not a good idea. Thoughts?In no particular order: 1) Adding ref to the call site is lexically similar to Hungarian notation and has all the drawbacks and advantages thereof. I know invoking Hungarian notation is almost an invocation of Godwin's law when it comes to programming syntax discussions, but Hungarian notation was introduced for a reason; there was a time when for large software projects it dramatically increases code comprehension (and thus quality) for the code reviewer and/or code maintainer. And that argument still stand today for anyone _not_ using a modern IDE. The primary reason Hungarian notation is disparaged today is that IDEs evolved beyond emacs, vim and notepad. Once they could tell the programmer with a tooltip what every variable's type was, the need to encode the type in the variable name vanished. Or more to the original point, modern IDEs already list function parameter's type and type modifiers (i.e. aka) as you type the function in so it's _always_ obvious what is ref/const/etc and what is not. And for the code reviewer, ref parameters could be auto highlighted/underlined/etc to easy their job. Yes, this issue does need to be addressed, but I don't think that this is fundamentally a language problem; it more a lack of modern tools for D. That reminds me, I need to check out the latest revision of Visual D. :) 2) It is perfectly possible to write functions in D that require explicit demarcation at the call site: int foo( int* v ) { return *x; } int y; int z = foo( y); Java, two questions are immediately raised in my mind. 3a) Does the asker simply want D to be more like language X? 3b) What do programmers experienced in X and in D/C++/C/etc think about that particular feature (good/bad/ugly)? 4) When presenting problematic language use case and an associated proposed solution, being light on details/analysis and missing the second most obvious drawbacks of your proposed solution will cause your argument to be dismissed by many people. In short, if you're not willing to fully think through your idea, why should we take the time to too? That aside, if you are serious about this topic, you might want to have a look at/submit a D improvement proposal (http://prowiki.org/wiki4d/wiki.cgi?LanguageDevel/DIPs).
Jan 15 2012
On 15/01/12 5:57 PM, Robert Jacques wrote:On Sun, 15 Jan 2012 07:36:53 -0600, Alex Rønne PetersenA fair point, but: a) D doesn't have much in terms of *free* highly-featured IDEs. b) Even if it did, lots of people still use emacs/vim. c) That does not help when glancing at code to find where a variable is modified.Thoughts?In no particular order: 1) Adding ref to the call site is lexically similar to Hungarian notation and has all the drawbacks and advantages thereof. I know invoking Hungarian notation is almost an invocation of Godwin's law when it comes to programming syntax discussions, but Hungarian notation was introduced for a reason; there was a time when for large software projects it dramatically increases code comprehension (and thus quality) for the code reviewer and/or code maintainer. And that argument still stand today for anyone _not_ using a modern IDE. The primary reason Hungarian notation is disparaged today is that IDEs evolved beyond emacs, vim and notepad. Once they could tell the programmer with a tooltip what every variable's type was, the need to encode the type in the variable name vanished. Or more to the original point, modern IDEs already list function parameter's type and type modifiers (i.e. aka) as you type the function in so it's _always_ obvious what is ref/const/etc and what is not. And for the code reviewer, ref parameters could be auto highlighted/underlined/etc to easy their job. Yes, this issue does need to be addressed, but I don't think that this is fundamentally a language problem; it more a lack of modern tools for D. That reminds me, I need to check out the latest revision of Visual D. :)2) It is perfectly possible to write functions in D that require explicit demarcation at the call site: int foo( int* v ) { return *x; } int y; int z = foo( y);True, but these aren't the same. Pointers can be reseated, ref parameters cannot. Pointers may also be null, encouraging needless null pointer checks.parameters. Anytime someone suggests a feature from another language, 3a) Does the asker simply want D to be more like language X?Perhaps, perhaps not. I think it is better to evaluate a suggestion on its merit and not on the suggester's motivation.3b) What do programmers experienced in X and in D/C++/C/etc think about that particular feature (good/bad/ugly)?I also know that people dislike using reference parameters in C++ due to the lack of visibility at the call site (causing them to use pointers).
Jan 15 2012
I also know that people dislike using reference parameters in C++ due to the lack of visibility at the call site (causing them to use pointers).Which is true for me. Every single one of my reference parameters is const ref or pointer.
Jan 15 2012
Tobias Pankrath:(What you do is also required by the Google C++ style guide.) So your experience favors the use of callsite "ref" for nonconst ref arguments :-) Bye, bearophileI also know that people dislike using reference parameters in C++ due to the lack of visibility at the call site (causing them to use pointers).Which is true for me. Every single one of my reference parameters is const ref or pointer.
Jan 15 2012
El 15/01/2012 20:04, Tobias Pankrath escribió:swap(ref a, ref b); // ?? No, thanks. swap(a, b); // obvious that the arguments will be mutated, and cleanerI also know that people dislike using reference parameters in C++ due to the lack of visibility at the call site (causing them to use pointers).Which is true for me. Every single one of my reference parameters is const ref or pointer.
Jan 15 2012
On Sun, 15 Jan 2012 12:27:46 -0600, Peter Alexander <peter.alexander.au gmail.com> wrote:On 15/01/12 5:57 PM, Robert Jacques wrote:Both DDT and Visual D are a *free* highly-featured IDE.On Sun, 15 Jan 2012 07:36:53 -0600, Alex Rønne PetersenA fair point, but: a) D doesn't have much in terms of *free* highly-featured IDEs.Thoughts?In no particular order: 1) Adding ref to the call site is lexically similar to Hungarian notation and has all the drawbacks and advantages thereof. I know invoking Hungarian notation is almost an invocation of Godwin's law when it comes to programming syntax discussions, but Hungarian notation was introduced for a reason; there was a time when for large software projects it dramatically increases code comprehension (and thus quality) for the code reviewer and/or code maintainer. And that argument still stand today for anyone _not_ using a modern IDE. The primary reason Hungarian notation is disparaged today is that IDEs evolved beyond emacs, vim and notepad. Once they could tell the programmer with a tooltip what every variable's type was, the need to encode the type in the variable name vanished. Or more to the original point, modern IDEs already list function parameter's type and type modifiers (i.e. aka) as you type the function in so it's _always_ obvious what is ref/const/etc and what is not. And for the code reviewer, ref parameters could be auto highlighted/underlined/etc to easy their job. Yes, this issue does need to be addressed, but I don't think that this is fundamentally a language problem; it more a lack of modern tools for D. That reminds me, I need to check out the latest revision of Visual D. :)b) Even if it did, lots of people still use emacs/vim.So, you're proposing to "fix" the language instead of using a better dev environment? Like stick shift drivers and *nix sys admins, coders who use emacs/vim actively acknowledge that the onus for writing correct code is on their shoulders; there are not going to be any red-squiggles, line re-formatting or code completion to "get in the way"/"help them".c) That does not help when glancing at code to find where a variable is modified.First, if the IDE colors every variable passed by ref blue, those are definitely going to jump off the page when glancing through code. Second, since when does _glancing_ at an unfamiliar piece of code every give meaningful results? Any reasonable code review (using a good IDE) will entail the reviewer checking the doc comments on any unfamiliar function.Well, if the final storage class was brought back into the language...2) It is perfectly possible to write functions in D that require explicit demarcation at the call site: int foo( int* v ) { return *x; } int y; int z = foo( y);True, but these aren't the same. Pointers can be reseated, ref parameters cannot.Pointers may also be null, encouraging needless null pointer checks.Needless null pointer checks are only a possible problem in release code; assert solves that problem nicely.Before I can evaluate your use case, let alone your suggestion I need to understand and filter your biases. It's really important to understand how much of a poster's frustration simply come from the cognitive disconnect between two different programming languages and the actual features and capabilities of D.parameters. Anytime someone suggests a feature from another language, 3a) Does the asker simply want D to be more like language X?Perhaps, perhaps not. I think it is better to evaluate a suggestion on its merit and not on the suggester's motivation.a bad thing as a positive response to ref gets mixed with mandated ref. It's good thing because there's probably a developer blog or two you could link too providing good support by industry experts for your argument.3b) What do programmers experienced in X and in D/C++/C/etc think about that particular feature (good/bad/ugly)?I also know that people dislike using reference parameters in C++ due to the lack of visibility at the call site (causing them to use pointers).From the C++ FQA on references: "Note: Old line C programmers sometimes don't like references since they provide reference semantics that isn't explicit in the caller's code. After some C++ experience, however, one quickly realizes this is a form of information hiding, which is an asset rather than a liability. E.g., programmers should write code in the language of the problem rather than the language of the machine." From Google's Style Guidelines: Within function parameter lists all references must be const: void Foo(const string &in, string *out); In fact it is a very strong convention in Google code that input arguments are values or const references while output arguments are pointers. Input parameters may be const pointers, but we never allow non-const reference parameters.
Jan 15 2012
Robert Jacques:1) Adding ref to the call site is lexically similar to Hungarian notation and has all the drawbacks and advantages thereof.The presence of "ref" at the call site is meant to be enforced by the type system of the compiler.Or more to the original point, modern IDEs already list function parameter's type and type modifiers (i.e. aka) as you type the function in so it's _always_ obvious what is ref/const/etc and what is not.the call site (but in some cases, where the use of ref is pervasive). Bye, bearophile
Jan 15 2012
On 1/15/2012 5:36 AM, Alex Rønne Petersen wrote:Hi, I don't know how many times I've made the mistake of passing a local variable to a function which takes a 'ref' parameter. Suddenly, local variables/fields are just mutating out of nowhere, because it's not at all obvious that a function you're calling is taking a 'ref' parameter. This is particularly true for std.utf.decode(). Yes, I realize I could look at the function declaration. Yes, I could read the docs too. But that doesn't prevent me from forgetting that a function takes a 'ref' parameter, and then doing the mistake again. The damage is done, and the time is wasted. I think D should allow 'ref' on call sites to prevent these mistakes. For example: string str = ...; size_t pos; auto chr = std.utf.decode(str, ref pos); Now it's much more obvious that the parameter is passed by reference and is going to be mutated. Ideally, this would not be optional, but rather *required*, but I realize that such a change would break a *lot* of code, so that's probably not a good idea. Thoughts?I suggested this a while ago but people acted as though I was talking about aliens...
Jan 15 2012
"Alex Rønne Petersen" <xtzgzorex gmail.com> wrote in message news:jeukpm$168v$1 digitalmars.com...Hi, I don't know how many times I've made the mistake of passing a local variable to a function which takes a 'ref' parameter. Suddenly, local variables/fields are just mutating out of nowhere, because it's not at all obvious that a function you're calling is taking a 'ref' parameter. This is particularly true for std.utf.decode(). Yes, I realize I could look at the function declaration. Yes, I could read the docs too. But that doesn't prevent me from forgetting that a function takes a 'ref' parameter, and then doing the mistake again. The damage is done, and the time is wasted. I think D should allow 'ref' on call sites to prevent these mistakes. For example: string str = ...; size_t pos; auto chr = std.utf.decode(str, ref pos); Now it's much more obvious that the parameter is passed by reference and is going to be mutated. Ideally, this would not be optional, but rather *required*, but I realize that such a change would break a *lot* of code, so that's probably not a good idea. Thoughts?wrong. That said though, I haven't personally run into this problem, and I've gotten used to not having "ref" or "out" on the caller's side. I wouldn't be opposed to the change though, even just as an optional warning.
Jan 15 2012
On 01/15/2012 10:39 PM, Nick Sabalausky wrote:"Alex Rønne Petersen"<xtzgzorex gmail.com> wrote in message news:jeukpm$168v$1 digitalmars.com...Hi, I don't know how many times I've made the mistake of passing a local variable to a function which takes a 'ref' parameter. Suddenly, local variables/fields are just mutating out of nowhere, because it's not at all obvious that a function you're calling is taking a 'ref' parameter. This is particularly true for std.utf.decode(). Yes, I realize I could look at the function declaration. Yes, I could read the docs too. But that doesn't prevent me from forgetting that a function takes a 'ref' parameter, and then doing the mistake again. The damage is done, and the time is wasted. I think D should allow 'ref' on call sites to prevent these mistakes. For example: string str = ...; size_t pos; auto chr = std.utf.decode(str, ref pos); Now it's much more obvious that the parameter is passed by reference and is going to be mutated. Ideally, this would not be optional, but rather *required*, but I realize that such a change would break a *lot* of code, so that's probably not a good idea. Thoughts?wrong.That said though, I haven't personally run into this problem, and I've gotten used to not having "ref" or "out" on the caller's side. I wouldn't be opposed to the change though, even just as an optional warning.
Jan 15 2012
On 01/15/2012 02:36 PM, Alex Rønne Petersen wrote:Hi, I don't know how many times I've made the mistake of passing a local variable to a function which takes a 'ref' parameter. Suddenly, local variables/fields are just mutating out of nowhere, because it's not at all obvious that a function you're calling is taking a 'ref' parameter. This is particularly true for std.utf.decode().Odd. I always thought the fact that std.utf.decode modifies the second parameter is very intuitive. (decoding cannot work nicely without it)Yes, I realize I could look at the function declaration. Yes, I could read the docs too. But that doesn't prevent me from forgetting that a function takes a 'ref' parameter, and then doing the mistake again. The damage is done, and the time is wasted.This is true for every part of a function interface. How can a programmer even understand what the function does if he forgets what the calling conventions are? Conversely, does a reminder of the calling conventions usually restore full knowledge of the semantics of the called function?I think D should allow 'ref' on call sites to prevent these mistakes. For example: string str = ...; size_t pos; auto chr = std.utf.decode(str, ref pos); Now it's much more obvious that the parameter is passed by reference and is going to be mutated. Ideally, this would not be optional, but rather *required*, but I realize that such a change would break a *lot* of code, so that's probably not a good idea. Thoughts?I personally think 'ref' at call site is pure syntax noise but I see that it might be useful to some in some cases. I'd prefer to leave it as-is, but I don't feel very strongly for either way. My preference would be [not allowed > enforced > ... > optional > optional with switch] However, it is very important not to do this to 'lazy'. Another thing that would have to be discussed: what happens to const ref parameters? It is very reasonable that someone will decide to change calling conventions from by value to by const ref or the other way round after profiling. It is very convenient that such a change is syntactically transparent to the caller and this should stay. It is even realistic that someone will decide to interchange by ref/by value, because there is no way to express 'I will not change the head level' in the current type system other than taking a parameter by value. Therefore introducing call-site ref would perhaps necessitate re-introducing 'final' for variables.
Jan 15 2012
On 15/01/12 10:10 PM, Timon Gehr wrote:Another thing that would have to be discussed: what happens to const ref parameters? It is very reasonable that someone will decide to change calling conventions from by value to by const ref or the other way round after profiling. It is very convenient that such a change is syntactically transparent to the caller and this should stay.Actually, that would be very dangerous. const ref does not have the privilege of being able to bind to rvalues in D like it does in C++. void foo(const ref int x) {...} foo(1); // this is legal in C++, but illegal in D In case, const ref would not require the ref at call site because there's no danger of it being modified.
Jan 15 2012
On 01/15/2012 11:41 PM, Peter Alexander wrote:On 15/01/12 10:10 PM, Timon Gehr wrote:Who on earth wants to change an int parameter from by value to by const ref? struct literals can bind to const ref parameters so there is absolutely no issue.Another thing that would have to be discussed: what happens to const ref parameters? It is very reasonable that someone will decide to change calling conventions from by value to by const ref or the other way round after profiling. It is very convenient that such a change is syntactically transparent to the caller and this should stay.Actually, that would be very dangerous. const ref does not have the privilege of being able to bind to rvalues in D like it does in C++. void foo(const ref int x) {...} foo(1); // this is legal in C++, but illegal in DIn case, const ref would not require the ref at call site because there's no danger of it being modified.The semantics are still not the same.
Jan 15 2012
On 01/15/2012 11:36 PM, Timon Gehr wrote:On 01/15/2012 11:41 PM, Peter Alexander wrote:(Even the claim that there is no danger of it being modified is plain wrong)On 15/01/12 10:10 PM, Timon Gehr wrote:Who on earth wants to change an int parameter from by value to by const ref? struct literals can bind to const ref parameters so there is absolutely no issue.Another thing that would have to be discussed: what happens to const ref parameters? It is very reasonable that someone will decide to change calling conventions from by value to by const ref or the other way round after profiling. It is very convenient that such a change is syntactically transparent to the caller and this should stay.Actually, that would be very dangerous. const ref does not have the privilege of being able to bind to rvalues in D like it does in C++. void foo(const ref int x) {...} foo(1); // this is legal in C++, but illegal in DIn case, const ref would not require the ref at call site because there's no danger of it being modified.The semantics are still not the same.
Jan 15 2012
On 15/01/12 10:36 PM, Timon Gehr wrote:On 01/15/2012 11:41 PM, Peter Alexander wrote:Are you sure about struct literals binding to const ref? I can't find anything in the language spec or TDPL that supports that claim. In fact, TDPL says: "If a function expects a ref, it accepts only "real" data, not temporaries; anything that's not an lvalue is rejected during compilation" Unfortunately it doesn't say anything explicitly about struct literals or const ref, but that would lead me to believe that they fall under the same rule. DMD allows struct literals to bind to const ref, but then again it also allows them to bind to ref, so I'm not sure how reliable that is. This should probably be clarified. It's kind of important.On 15/01/12 10:10 PM, Timon Gehr wrote:Who on earth wants to change an int parameter from by value to by const ref? struct literals can bind to const ref parameters so there is absolutely no issue.Another thing that would have to be discussed: what happens to const ref parameters? It is very reasonable that someone will decide to change calling conventions from by value to by const ref or the other way round after profiling. It is very convenient that such a change is syntactically transparent to the caller and this should stay.Actually, that would be very dangerous. const ref does not have the privilege of being able to bind to rvalues in D like it does in C++. void foo(const ref int x) {...} foo(1); // this is legal in C++, but illegal in D
Jan 15 2012
On 01/16/2012 12:39 AM, Peter Alexander wrote:On 15/01/12 10:36 PM, Timon Gehr wrote:Well, struct literals are lvalues, at least in DMD.On 01/15/2012 11:41 PM, Peter Alexander wrote:Are you sure about struct literals binding to const ref? I can't find anything in the language spec or TDPL that supports that claim. In fact, TDPL says: "If a function expects a ref, it accepts only "real" data, not temporaries; anything that's not an lvalue is rejected during compilation"On 15/01/12 10:10 PM, Timon Gehr wrote:Who on earth wants to change an int parameter from by value to by const ref? struct literals can bind to const ref parameters so there is absolutely no issue.Another thing that would have to be discussed: what happens to const ref parameters? It is very reasonable that someone will decide to change calling conventions from by value to by const ref or the other way round after profiling. It is very convenient that such a change is syntactically transparent to the caller and this should stay.Actually, that would be very dangerous. const ref does not have the privilege of being able to bind to rvalues in D like it does in C++. void foo(const ref int x) {...} foo(1); // this is legal in C++, but illegal in DUnfortunately it doesn't say anything explicitly about struct literals or const ref, but that would lead me to believe that they fall under the same rule. DMD allows struct literals to bind to const ref, but then again it also allows them to bind to ref, so I'm not sure how reliable that is. This should probably be clarified. It's kind of important.I agree, but banning it would be an arbitrary and pointless restriction.
Jan 15 2012
On Monday, January 16, 2012 00:41:14 Timon Gehr wrote:Well, struct literals are lvalues, at least in DMD.Yeah. I don't understand that. I've argued about it with Walter before. Apparently they are in C++ as well. I don't understand it. It makes it so that void func(ref S val) S bar(); works with func(S(42)); but not func(bar()); It seems completely arbitrary to me that it works this way and has IMHO _zero_ benefits. And I know that newbies have run into the problem and been completely confused by it (e.g. http://stackoverflow.com/questions/6986175/const-ref-and- rvalue-in-d ). _I_'ve been confused by it. I was stunned to find out that there was _any_ difference in the language between a struct literal and an identical struct returned from a function. It's not as big an issue in C++, because using & is fairly rare in C++ unless its const, and const & will take temporaries. But in D, it's _definitely_ an issue IMHO. I really think that struct literals should be considered rvalues. I do _not_ understand why they aren't or why anyone ever thought that it was a good idea for them to be lvalues. - Jonathan M Davis
Jan 15 2012
On 15/01/12 11:56 PM, Jonathan M Davis wrote:On Monday, January 16, 2012 00:41:14 Timon Gehr wrote:In C++, struct literals are rvalues. C++ just has a special rule that const references can bind to rvalues (but non-const references cannot), and another special rule that when a const reference binds to a temporary it extends the life of the temporary. The benefit in C++ is so that you can write one function that takes a const reference and it works with rvalues as well as lvalues. Taking by value would be too expensive a lot of the time.Well, struct literals are lvalues, at least in DMD.Yeah. I don't understand that. I've argued about it with Walter before. Apparently they are in C++ as well. I don't understand it. It makes it so that
Jan 15 2012
On 01/16/2012 01:30 AM, Peter Alexander wrote:On 15/01/12 11:56 PM, Jonathan M Davis wrote:In C++, a struct literal can be on the lhs of an expression (because of the implicit copy assignment operator) but you cannot take it's address unless you pass it by const& ;DOn Monday, January 16, 2012 00:41:14 Timon Gehr wrote:In C++, struct literals are rvalues. C++ just has a special rule that const references can bind to rvalues (but non-const references cannot), and another special rule that when a const reference binds to a temporary it extends the life of the temporary.Well, struct literals are lvalues, at least in DMD.Yeah. I don't understand that. I've argued about it with Walter before. Apparently they are in C++ as well. I don't understand it. It makes it so thatThe benefit in C++ is so that you can write one function that takes a const reference and it works with rvalues as well as lvalues. Taking by value would be too expensive a lot of the time.In D there is no such thing as a C++ const reference, therefore I think it is reasonable that struct literals are lvalues.
Jan 15 2012
On 1/15/12 6:30 PM, Peter Alexander wrote:On 15/01/12 11:56 PM, Jonathan M Davis wrote:That's a bad rule that we shouldn't copy. AndreiOn Monday, January 16, 2012 00:41:14 Timon Gehr wrote:In C++, struct literals are rvalues. C++ just has a special rule that const references can bind to rvalues (but non-const references cannot),Well, struct literals are lvalues, at least in DMD.Yeah. I don't understand that. I've argued about it with Walter before. Apparently they are in C++ as well. I don't understand it. It makes it so that
Jan 15 2012
On 01/16/2012 01:35 AM, Andrei Alexandrescu wrote:On 1/15/12 6:30 PM, Peter Alexander wrote:What do you think is an optimal rule regarding struct literals/lvalues/rvalues and ref parameters?On 15/01/12 11:56 PM, Jonathan M Davis wrote:That's a bad rule that we shouldn't copy. AndreiOn Monday, January 16, 2012 00:41:14 Timon Gehr wrote:In C++, struct literals are rvalues. C++ just has a special rule that const references can bind to rvalues (but non-const references cannot),Well, struct literals are lvalues, at least in DMD.Yeah. I don't understand that. I've argued about it with Walter before. Apparently they are in C++ as well. I don't understand it. It makes it so that
Jan 15 2012
On 1/15/12 6:38 PM, Timon Gehr wrote:On 01/16/2012 01:35 AM, Andrei Alexandrescu wrote:auto ref AndreiOn 1/15/12 6:30 PM, Peter Alexander wrote:What do you think is an optimal rule regarding struct literals/lvalues/rvalues and ref parameters?On 15/01/12 11:56 PM, Jonathan M Davis wrote:That's a bad rule that we shouldn't copy. AndreiOn Monday, January 16, 2012 00:41:14 Timon Gehr wrote:In C++, struct literals are rvalues. C++ just has a special rule that const references can bind to rvalues (but non-const references cannot),Well, struct literals are lvalues, at least in DMD.Yeah. I don't understand that. I've argued about it with Walter before. Apparently they are in C++ as well. I don't understand it. It makes it so that
Jan 15 2012
On 01/16/2012 02:00 AM, Andrei Alexandrescu wrote:On 1/15/12 6:38 PM, Timon Gehr wrote:But that only works for templates?On 01/16/2012 01:35 AM, Andrei Alexandrescu wrote:auto ref AndreiOn 1/15/12 6:30 PM, Peter Alexander wrote:What do you think is an optimal rule regarding struct literals/lvalues/rvalues and ref parameters?On 15/01/12 11:56 PM, Jonathan M Davis wrote:That's a bad rule that we shouldn't copy. AndreiOn Monday, January 16, 2012 00:41:14 Timon Gehr wrote:In C++, struct literals are rvalues. C++ just has a special rule that const references can bind to rvalues (but non-const references cannot),Well, struct literals are lvalues, at least in DMD.Yeah. I don't understand that. I've argued about it with Walter before. Apparently they are in C++ as well. I don't understand it. It makes it so that
Jan 15 2012
On 1/15/12 7:21 PM, Timon Gehr wrote:On 01/16/2012 02:00 AM, Andrei Alexandrescu wrote:For non-templates, if it's important to distinguish between lvalues and rvalues, use two overloads. AndreiOn 1/15/12 6:38 PM, Timon Gehr wrote:But that only works for templates?On 01/16/2012 01:35 AM, Andrei Alexandrescu wrote:auto ref AndreiOn 1/15/12 6:30 PM, Peter Alexander wrote:What do you think is an optimal rule regarding struct literals/lvalues/rvalues and ref parameters?On 15/01/12 11:56 PM, Jonathan M Davis wrote:That's a bad rule that we shouldn't copy. AndreiOn Monday, January 16, 2012 00:41:14 Timon Gehr wrote:In C++, struct literals are rvalues. C++ just has a special rule that const references can bind to rvalues (but non-const references cannot),Well, struct literals are lvalues, at least in DMD.Yeah. I don't understand that. I've argued about it with Walter before. Apparently they are in C++ as well. I don't understand it. It makes it so that
Jan 18 2012
On 01/18/2012 06:13 PM, Andrei Alexandrescu wrote:On 1/15/12 7:21 PM, Timon Gehr wrote:Currently 'auto ref' gives a compile error if used in a non-templated function parameter list. What are the semantics of 'auto ref' you have in mind? Are they specified somewhere?On 01/16/2012 02:00 AM, Andrei Alexandrescu wrote:For non-templates, if it's important to distinguish between lvalues and rvalues, use two overloads. AndreiOn 1/15/12 6:38 PM, Timon Gehr wrote:But that only works for templates?On 01/16/2012 01:35 AM, Andrei Alexandrescu wrote:auto ref AndreiOn 1/15/12 6:30 PM, Peter Alexander wrote:What do you think is an optimal rule regarding struct literals/lvalues/rvalues and ref parameters?On 15/01/12 11:56 PM, Jonathan M Davis wrote:That's a bad rule that we shouldn't copy. AndreiOn Monday, January 16, 2012 00:41:14 Timon Gehr wrote:In C++, struct literals are rvalues. C++ just has a special rule that const references can bind to rvalues (but non-const references cannot),Well, struct literals are lvalues, at least in DMD.Yeah. I don't understand that. I've argued about it with Walter before. Apparently they are in C++ as well. I don't understand it. It makes it so that
Jan 18 2012
On 1/18/12 11:27 AM, Timon Gehr wrote:On 01/18/2012 06:13 PM, Andrei Alexandrescu wrote:I meant two overloads that don't use auto ref: void fun(S); void fun(ref S); AndreiFor non-templates, if it's important to distinguish between lvalues and rvalues, use two overloads. AndreiCurrently 'auto ref' gives a compile error if used in a non-templated function parameter list. What are the semantics of 'auto ref' you have in mind? Are they specified somewhere?
Jan 18 2012
On 16/01/12 12:35 AM, Andrei Alexandrescu wrote:On 1/15/12 6:30 PM, Peter Alexander wrote:I agree.On 15/01/12 11:56 PM, Jonathan M Davis wrote:That's a bad rule that we shouldn't copy.On Monday, January 16, 2012 00:41:14 Timon Gehr wrote:In C++, struct literals are rvalues. C++ just has a special rule that const references can bind to rvalues (but non-const references cannot),Well, struct literals are lvalues, at least in DMD.Yeah. I don't understand that. I've argued about it with Walter before. Apparently they are in C++ as well. I don't understand it. It makes it so that
Jan 15 2012
On 01/15/2012 11:10 PM, Timon Gehr wrote:On 01/15/2012 02:36 PM, Alex Rønne Petersen wrote:Oh, and furthermore it would give rise to abominations such as: auto ref wrap(alias foo,T...)(auto ref T args){ return foo(auto ref args); } *shudder*. What does 'auto ref' even mean if 'ref' is required for ref parameters at call site? I think the best answers would silently break existing code.Hi, I don't know how many times I've made the mistake of passing a local variable to a function which takes a 'ref' parameter. Suddenly, local variables/fields are just mutating out of nowhere, because it's not at all obvious that a function you're calling is taking a 'ref' parameter. This is particularly true for std.utf.decode().Odd. I always thought the fact that std.utf.decode modifies the second parameter is very intuitive. (decoding cannot work nicely without it)Yes, I realize I could look at the function declaration. Yes, I could read the docs too. But that doesn't prevent me from forgetting that a function takes a 'ref' parameter, and then doing the mistake again. The damage is done, and the time is wasted.This is true for every part of a function interface. How can a programmer even understand what the function does if he forgets what the calling conventions are? Conversely, does a reminder of the calling conventions usually restore full knowledge of the semantics of the called function?I think D should allow 'ref' on call sites to prevent these mistakes. For example: string str = ...; size_t pos; auto chr = std.utf.decode(str, ref pos); Now it's much more obvious that the parameter is passed by reference and is going to be mutated. Ideally, this would not be optional, but rather *required*, but I realize that such a change would break a *lot* of code, so that's probably not a good idea. Thoughts?I personally think 'ref' at call site is pure syntax noise but I see that it might be useful to some in some cases. I'd prefer to leave it as-is, but I don't feel very strongly for either way. My preference would be [not allowed > enforced > ... > optional > optional with switch] However, it is very important not to do this to 'lazy'. Another thing that would have to be discussed: what happens to const ref parameters? It is very reasonable that someone will decide to change calling conventions from by value to by const ref or the other way round after profiling. It is very convenient that such a change is syntactically transparent to the caller and this should stay. It is even realistic that someone will decide to interchange by ref/by value, because there is no way to express 'I will not change the head level' in the current type system other than taking a parameter by value. Therefore introducing call-site ref would perhaps necessitate re-introducing 'final' for variables.
Jan 15 2012
On Sunday, January 15, 2012 14:36:53 Alex R=C3=B8nne Petersen wrote:Thoughts?This was discussed before, and I'm still completely against it. It _onl= y_ has=20 value IMHO if it's required, and even then, I don't like the idea. If it's _not_ required, then you don't know _still_ don't know whether = a=20 function takes a ref or not. The lack of ref at the call site means _no= thing_.=20 Does func(var); alter var? You can't know. If it's func(ref var); then yes, you _do_ know that it's being altered. But this just gives yo= u a=20 false sense of security. You _still_ need to check _every_ function cal= l which=20 isn't marked with ref whether it takes its arguments by ref or not. If = it were=20 required, then you would know that func(var); doesn't take var by ref and that func(ref var); _does_ take var by ref. So, in that case, it's _not_ a false sense of=20= security. It _actually_ guarantees something. So, it _does_ have some v= alue in=20 that case. But as long as it's optional, it's worse than not having it = IMHO. Now, personally, I don't like it regardless. It's makes function calls = that=20 much noisier at minimal benefit. Yes, upon occasion, I screw up and don= 't=20 realize that a function takes an argument by ref, but that's something = that I=20 _should_ know. It has a definite effect on what the function does, and = I should=20 be aware of it. So, I'm completely against this feature. - Jonathan M Davis
Jan 15 2012
2012/1/15 Alex R=F8nne Petersen <xtzgzorex gmail.com>:Hi, I don't know how many times I've made the mistake of passing a local variable to a function which takes a 'ref' parameter. Suddenly, local variables/fields are just mutating out of nowhere, because it's not at al=lobvious that a function you're calling is taking a 'ref' parameter. This =isparticularly true for std.utf.decode(). Yes, I realize I could look at the function declaration. Yes, I could rea=dthe docs too. But that doesn't prevent me from forgetting that a function takes a 'ref' parameter, and then doing the mistake again. The damage is done, and the time is wasted. I think D should allow 'ref' on call sites to prevent these mistakes. For example: string str =3D ...; size_t pos; auto chr =3D std.utf.decode(str, ref pos); Now it's much more obvious that the parameter is passed by reference and =isgoing to be mutated. Ideally, this would not be optional, but rather *required*, but I realize that such a change would break a *lot* of code, so that's probably not a good idea. Thoughts? -- - AlexI don't see how call cite ref will help the issue. If you don't read ddoc, how will you know what exactly function does with it's ref parameter - statistically? Knowing that function takes parameter by ref doesn't help understanding it's logic. Also, knowing that function doesn't take any ref parameters doesn't mean you don't need to read it's documentation.
Jan 15 2012
On 16-01-2012 02:37, Mail Mantis wrote:2012/1/15 Alex Rønne Petersen<xtzgzorex gmail.com>:You may remember what the function does, but forget that it mutates an input parameter. -- - AlexHi, I don't know how many times I've made the mistake of passing a local variable to a function which takes a 'ref' parameter. Suddenly, local variables/fields are just mutating out of nowhere, because it's not at all obvious that a function you're calling is taking a 'ref' parameter. This is particularly true for std.utf.decode(). Yes, I realize I could look at the function declaration. Yes, I could read the docs too. But that doesn't prevent me from forgetting that a function takes a 'ref' parameter, and then doing the mistake again. The damage is done, and the time is wasted. I think D should allow 'ref' on call sites to prevent these mistakes. For example: string str = ...; size_t pos; auto chr = std.utf.decode(str, ref pos); Now it's much more obvious that the parameter is passed by reference and is going to be mutated. Ideally, this would not be optional, but rather *required*, but I realize that such a change would break a *lot* of code, so that's probably not a good idea. Thoughts? -- - AlexI don't see how call cite ref will help the issue. If you don't read ddoc, how will you know what exactly function does with it's ref parameter - statistically? Knowing that function takes parameter by ref doesn't help understanding it's logic. Also, knowing that function doesn't take any ref parameters doesn't mean you don't need to read it's documentation.
Jan 15 2012
On 01/16/2012 08:31 AM, Alex Rønne Petersen wrote:On 16-01-2012 02:37, Mail Mantis wrote:This statement is self-contradictory.2012/1/15 Alex Rønne Petersen<xtzgzorex gmail.com>:You may remember what the function does, but forget that it mutates an input parameter. -- - AlexHi, I don't know how many times I've made the mistake of passing a local variable to a function which takes a 'ref' parameter. Suddenly, local variables/fields are just mutating out of nowhere, because it's not at all obvious that a function you're calling is taking a 'ref' parameter. This is particularly true for std.utf.decode(). Yes, I realize I could look at the function declaration. Yes, I could read the docs too. But that doesn't prevent me from forgetting that a function takes a 'ref' parameter, and then doing the mistake again. The damage is done, and the time is wasted. I think D should allow 'ref' on call sites to prevent these mistakes. For example: string str = ...; size_t pos; auto chr = std.utf.decode(str, ref pos); Now it's much more obvious that the parameter is passed by reference and is going to be mutated. Ideally, this would not be optional, but rather *required*, but I realize that such a change would break a *lot* of code, so that's probably not a good idea. Thoughts? -- - AlexI don't see how call cite ref will help the issue. If you don't read ddoc, how will you know what exactly function does with it's ref parameter - statistically? Knowing that function takes parameter by ref doesn't help understanding it's logic. Also, knowing that function doesn't take any ref parameters doesn't mean you don't need to read it's documentation.
Jan 16 2012
On 1/15/2012 5:37 PM, Mail Mantis wrote:I don't see how call cite ref will help the issue. If you don't read ddoc, how will you know what exactly function does with it's ref parameter - statistically? Knowing that function takes parameter by ref doesn't help understanding it's logic. Also, knowing that function doesn't take any ref parameters doesn't mean you don't need to read it's documentation."If the documentation explains it, the code doesn't need to." ?!?!? Documentation is frequently out of date, but code isn't. And ideally, the code wouldn't NEED documentation, BECAUSE it SAYS what it's doing.
Jan 16 2012
2012/1/17 Mehrdad <wfunction hotmail.com>:?!?!? Documentation is frequently out of date, but code isn't. And ideally, the code wouldn't NEED documentation, BECAUSE it SAYS what it's doing.Maybe - if you have access to function's source text. But we were talking about a specific feature on callers side. "ref" stated at call site doesn't say what function is doing, it only tells that function returns one of it's results in specific parameter. That might be occasionally useful, but it is not worth extra syntax it introduces.
Jan 16 2012