www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - simple definition of "in" function parameters, and default "ref"

reply John Nixon <john.h.nixon1 gmail.com> writes:
I have just read that the storage class "in" for function 
parameters has not yet been properly implemented. From its simple 
meaning as a one-way flow of information into a function from the 
calling function, surely it should be implemented by copying the 
argument, as is now done by default for all function arguments. 
Note this has a distinct meaning from the far more restrictive 
"const" that enforces the variable to remain constant throughout 
its lifetime while the called function is running. It would then 
naturally complement "out" and provide a simple semantics in the 
function signature to aid program design.
It would also make it simpler if there was no difference between 
the behaviour of reference and value types in function parameters 
with default passing by reference. This would make the storage 
class "none" correspond to "in" and "out". At present if this is 
wanted, sometimes the keyword "ref" has to be used, and sometimes 
it is not necessary (depending on whether the type is value or 
reference).
A simplified language would make it easier to develop programs to 
check programmer's code.
Oct 27 2018
next sibling parent Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Saturday, 27 October 2018 at 11:48:55 UTC, John Nixon wrote:
 I have just read that the storage class "in" for function 
 parameters has not yet been properly implemented. From its 
 simple meaning as a one-way flow of information into a function 
 from the calling function, surely it should be implemented by 
 copying the argument, as is now done by default for all 
 function arguments.
``` void foo(T)(in T value) { /* ... */ } int i; Object o; // 1 foo(&i); // 2 foo(o); ``` Are you suggesting that for (1), typeof(value) in foo should be `int*`? And that for (2) typeof (value) in foo should be `Object`? This can't work. You can't implicitly "copy" a pointee or a referree, you can only copy the respective bits of the pointer/reference. If you do that and strip `const` from the argument, you're left with a non-const pointer or reference, respectively, which would make `in` pointless. From the spec (https://dlang.org/spec/function.html#param-storage): "[in] defined as scope const. However in has not yet been properly implemented so it's current implementation is equivalent to const. It is recommended to avoid using in until it is properly defined and implemented. Use scope const or const explicitly instead." Translation: a long time ago, `in` was supposed to be a shorthand for `const scope`. Later on Walter in his patches started treating `in` as just `const`, as doing otherwise would "break too much [third-party user] code". Current wording indicates that that could've been a mistake.
 It would also make it simpler if there was no difference 
 between the behaviour of reference and value types in function 
 parameters with default passing by reference.
Now that is a catastrophe-breaking-change suggestion if I've ever seen one.
Oct 27 2018
prev sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Saturday, October 27, 2018 5:48:55 AM MDT John Nixon via Digitalmars-d 
wrote:
 I have just read that the storage class "in" for function
 parameters has not yet been properly implemented. From its simple
 meaning as a one-way flow of information into a function from the
 calling function, surely it should be implemented by copying the
 argument, as is now done by default for all function arguments.
 Note this has a distinct meaning from the far more restrictive
 "const" that enforces the variable to remain constant throughout
 its lifetime while the called function is running. It would then
 naturally complement "out" and provide a simple semantics in the
 function signature to aid program design.
 It would also make it simpler if there was no difference between
 the behaviour of reference and value types in function parameters
 with default passing by reference. This would make the storage
 class "none" correspond to "in" and "out". At present if this is
 wanted, sometimes the keyword "ref" has to be used, and sometimes
 it is not necessary (depending on whether the type is value or
 reference).
 A simplified language would make it easier to develop programs to
 check programmer's code.
in was supposed to be identical to const scope. However, scope has never really done much aside for delegates and was not very well defined, so it's pretty much just been the same as const. Lots of people have used it either because they liked the idea that it was the counterpart to out or because they thought that they understood what how it was supposed to work and wanted whatever behavior that was, but it wasn't actually properly defined and has always just been the same as const for everything other than delegates. So, arguably, no one should have been using it, but lots of people have been. However, DIP 1000 actually defines what scope means and makes it work for more than just delegates, and the result would be that making in actually mean const scope as originally intended would then break a _lot_ of code. _Some_ of that code should be broken, because the author used scope in a way that's close enough to what scope is actually going to mean that the fact that the code doesn't compile would mean that a bug will have been caught, but in the vast majority of cases, in was used without a proper understanding of what it would mean - especially since scope was not properly defined, and as it is, now that scope _does_ have a proper definition with DIP 1000, most people don't understand it very well outside of simple examples, meaning that it's hard to correctly write code that uses scope with -dip1000 even now. So, it's _highly_ unlikely that existing code using in is using it in a way that's going to be compatible with scope. So, the current plan is for in to remain as const rather than to become const scope, because it would mean far less code breakage. Some people are not very happy about that, and the plan may yet change, but either way, there's pretty much no way that in is going to be changed to mean something else entirely at this point. Doing so would break even more code than actually making it mean const scope as originally intended would. - Jonathan M Davis
Oct 27 2018
next sibling parent John Nixon <john.h.nixon1 gmail.com> writes:
Thank you for both the detailed explanations in reply to my post. 
They are in places a little over my head. My motivation was to 
make D semantically as simple as possible. John Nixon
Oct 27 2018
prev sibling parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Saturday, 27 October 2018 at 13:28:20 UTC, Jonathan M Davis 
wrote:
 On Saturday, October 27, 2018 5:48:55 AM MDT John Nixon via 
 Digitalmars-d wrote:
 I have just read that the storage class "in" for function
 parameters has not yet been properly implemented. From its 
 simple
 meaning as a one-way flow of information into a function from 
 the
 calling function, surely it should be implemented by copying 
 the
 argument, as is now done by default for all function arguments.
 Note this has a distinct meaning from the far more restrictive
 "const" that enforces the variable to remain constant 
 throughout
 its lifetime while the called function is running. It would 
 then
 naturally complement "out" and provide a simple semantics in 
 the
 function signature to aid program design.
 It would also make it simpler if there was no difference 
 between
 the behaviour of reference and value types in function 
 parameters
 with default passing by reference. This would make the storage
 class "none" correspond to "in" and "out". At present if this 
 is
 wanted, sometimes the keyword "ref" has to be used, and 
 sometimes
 it is not necessary (depending on whether the type is value or
 reference).
 A simplified language would make it easier to develop programs 
 to
 check programmer's code.
in was supposed to be identical to const scope. However, scope has never really done much aside for delegates and was not very well defined, so it's pretty much just been the same as const. Lots of people have used it either because they liked the idea that it was the counterpart to out or because they thought that they understood what how it was supposed to work and wanted whatever behavior that was, but it wasn't actually properly defined and has always just been the same as const for everything other than delegates. So, arguably, no one should have been using it, but lots of people have been. However, DIP 1000 actually defines what scope means and makes it work for more than just delegates, and the result would be that making in actually mean const scope as originally intended would then break a _lot_ of code. _Some_ of that code should be broken, because the author used scope in a way that's close enough to what scope is actually going to mean that the fact that the code doesn't compile would mean that a bug will have been caught, but in the vast majority of cases, in was used without a proper understanding of what it would mean - especially since scope was not properly defined, and as it is, now that scope _does_ have a proper definition with DIP 1000, most people don't understand it very well outside of simple examples, meaning that it's hard to correctly write code that uses scope with -dip1000 even now. So, it's _highly_ unlikely that existing code using in is using it in a way that's going to be compatible with scope. So, the current plan is for in to remain as const rather than to become const scope, because it would mean far less code breakage. Some people are not very happy about that, and the plan may yet change, but either way, there's pretty much no way that in is going to be changed to mean something else entirely at this point. Doing so would break even more code than actually making it mean const scope as originally intended would. - Jonathan M Davis
The "in" feature perplex me here, I never understand why we couldn't simply write "const scope" instead of "in". Seems it better off to mean "(foreach var a in x)" for readability sake instead of using as a parameter that no-one seems to be hardly using.
Oct 27 2018
next sibling parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Saturday, October 27, 2018 4:32:48 PM MDT 12345swordy via Digitalmars-d 
wrote:
 The "in" feature perplex me here, I never understand why we
 couldn't simply write "const scope" instead of "in". Seems it
 better off to mean "(foreach var a in x)" for readability sake
 instead of using as a parameter that no-one seems to be hardly
 using.
As I understand it, the in keyword was used on parameters in D1 to mean something something similar to const, but whatever it meant, it wasn't something that was going to match up with D2. And for D2, it was decided to make it mean const scope in an attempt to make porting code from D1 to D2 easier. However, with everything going on early in D2 development (and in the years since), scope was not exactly a priority, and so it wasn't really fully sorted out and was never focused on until Walter worked on DIP 1000, meaning that while in was supposed to mean const scope, it never really properly did. It did for delegates, so it wasn't identical to const but was effectively identical to const everywhere else making it just plain weird in general. Personally, I think that having a keyword mean two other keywords is a terrible idea in the first place, but there are definitely folks who like the idea. If in were added to D2 without its history in D1, I expect that the situation would have been quite different. Regardless, none of that would have had any effect on foreach, because in is already used as a keyword elsewhere in the language and in places similar to foreach - e.g. it's an operator. if(auto value = key in aa) and that usage arguably clashes far more with the idea of using in with foreach than having used it with function parameters. Also, whether using in with foreach would have been easier to read is highly debatable. Personally, I find in harder to read, not easier. If anything, I would have expected the debate to have been over whether it should have been a colon instead of a semicolon, since IIRC most other major C-derived languages have gone with the colon, whereas D went with the semicolon. But in the end, it's mostly a matter of personal preference. ;, :, and in all _can_ work, and the differences are primarily cosmetic. - Jonathan M Davis
Oct 27 2018
prev sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
On Saturday, 27 October 2018 at 22:32:48 UTC, 12345swordy wrote:
 The "in" feature perplex me here, I never understand why we 
 couldn't simply write "const scope" instead of "in".
`in` is a counterpoint to `out`. `out` means the function is going to write a value to that variable as output. `in` means the function is going to look at the value, but otherwise not touch it.
 better off to mean "(foreach var a in x)" for readability sake 
 instead of using as a parameter that no-one seems to be hardly 
 using.
there's no reason it couldn't be both.
Oct 27 2018