www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Wishlist proposal, documenting fn arg as in or out or mod

reply Cecil Ward <cecil cecilward.com> writes:
I would love to be able to document my arguments as in or out but 
also as read-write (like var in pascal, like fortran (?) and C++ 
D ref.

We already have "in". Good thing.

However it has got mixed up with const so that you can’t declare 
something as both. Is that right? I would like the compilers not 
to complain if something is declared as "in const" as there are 
two independent _intentions_ here, even though of course in 
implies const. Apart from that in is great. I use it everywhere. 
Small tweak.

Out is perfect as is.

However I hate using ref for input-output arguments as it isn’t 
visible at the call site and a ref could be just 
ref-for-implementation as in where you want to pass by reference 
to avoid copying a large object, but that has nothing to do with 
documenting the intention behind the in / out marking of the arg. 
Leave ref as it is for those who like it.

So I propose a new keyword either something like modified or mod 
or rw or input_output. Beauty contest, I don’t care what wins. 
(Shame inout is already taken.)

So my fn might look like

void myfn( in T1 InputArg, in const ref InputArray1, rw Modify, 
out result )

What do you think?

Then D would be as good as Ada in this respect, if I can remember 
from 40 years ago. ;-)
Jun 20 2023
next sibling parent reply Dom DiSc <dominikus scherkl.de> writes:
On Tuesday, 20 June 2023 at 15:01:17 UTC, Cecil Ward wrote:

 void myfn( in T1 InputArg, in const ref InputArray1, rw Modify, 
 out result )
why not ```d void myfn(in T1 InputArg, const ref T2 InputArray1, ref T3 Modify, out T4 result); ``` a "const ref" is of course read only, and a simple "ref" is expected to be modified by the function (else you would have made it const, wouldn't you?). so you have read only (const ref), write only (out) and read/write (ref) plus additionally "in" (which may be ref or not, based on what the compiler sees best fit). I can't see the necessity for a new keyword. By the way, what should "const in" be for?!? "in" is already not to be modified by the function. It is only there to allow both l-values and r-values to be used as input.
Jun 20 2023
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 6/20/23 17:56, Dom DiSc wrote:
 
 a "const ref" is of course read only, and a simple "ref" is expected to 
 be modified by the function (else you would have made it const, wouldn't 
 you?).
Absolutely not.
Jun 20 2023
prev sibling parent user456 <user456 123.de> writes:
On Tuesday, 20 June 2023 at 15:56:55 UTC, Dom DiSc wrote:
 On Tuesday, 20 June 2023 at 15:01:17 UTC, Cecil Ward wrote:

 void myfn( in T1 InputArg, in const ref InputArray1, rw 
 Modify, out result )
why not ```d void myfn(in T1 InputArg, const ref T2 InputArray1, ref T3 Modify, out T4 result); ``` a "const ref" is of course read only, and a simple "ref" is expected to be modified by the function (else you would have made it const, wouldn't you?).
`const ref` vs `const` is about the size of the parameter. Also maybe a bit about the position in the parameter list.
Jun 20 2023
prev sibling next sibling parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Tuesday, 20 June 2023 at 15:01:17 UTC, Cecil Ward wrote:
 So I propose a new keyword either something like modified or 
 mod or rw or input_output. Beauty contest, I don’t care what 
 wins. (Shame inout is already taken.)
Fun fact: the reason `inout` is a keyword in D is that this is what it used to be. Back on the old days, `inout` meant `ref`. But people kept asking so it got renamed to ref, and then inout was eventually reassigned to the const forwarding thing it is now (which was originally gonna be called `return` but never got implemented, and now `return` is used to indicate the lifetime of the parameter is the same as the return value, lolol)
Jun 20 2023
parent reply ryuukk_ <ryuukk.dev gmail.com> writes:
On Tuesday, 20 June 2023 at 16:12:35 UTC, Adam D Ruppe wrote:
 On Tuesday, 20 June 2023 at 15:01:17 UTC, Cecil Ward wrote:
 So I propose a new keyword either something like modified or 
 mod or rw or input_output. Beauty contest, I don’t care what 
 wins. (Shame inout is already taken.)
Fun fact: the reason `inout` is a keyword in D is that this is what it used to be. Back on the old days, `inout` meant `ref`. But people kept asking so it got renamed to ref, and then inout was eventually reassigned to the const forwarding thing it is now (which was originally gonna be called `return` but never got implemented, and now `return` is used to indicate the lifetime of the parameter is the same as the return value, lolol)
``return`` thing is the most stupid thing ever, whoever approved this needs to stop
Jun 20 2023
parent Cecil Ward <cecil cecilward.com> writes:
On Tuesday, 20 June 2023 at 22:17:13 UTC, ryuukk_ wrote:
 On Tuesday, 20 June 2023 at 16:12:35 UTC, Adam D Ruppe wrote:
 On Tuesday, 20 June 2023 at 15:01:17 UTC, Cecil Ward wrote:
 [...]
Fun fact: the reason `inout` is a keyword in D is that this is what it used to be. Back on the old days, `inout` meant `ref`. But people kept asking so it got renamed to ref, and then inout was eventually reassigned to the const forwarding thing it is now (which was originally gonna be called `return` but never got implemented, and now `return` is used to indicate the lifetime of the parameter is the same as the return value, lolol)
``return`` thing is the most stupid thing ever, whoever approved this needs to stop
The Horror!
Jun 20 2023
prev sibling next sibling parent reply Dom DiSc <dominikus scherkl.de> writes:
Just to put it in clearer words:

On Tuesday, 20 June 2023 at 15:01:17 UTC, Cecil Ward wrote:
 I would love to be able to document my arguments as in or out 
 but also as read-write
This is what "ref" is for.
 We already have "in". Good thing.

 However it has got mixed up with const so that you can’t 
 declare something as both.
Hurray! I'm so glad this is not allowed. "in" means const. There is no gain in "const const".
 However I hate using ref for input-output arguments as it isn’t 
 visible at the call site
This is true for all annotations.
 and a ref could be just ref-for-implementation
Sorry, but if a function takes a "ref" that it never modifies, I would call this simply a bug. It prevents you from calling it with const or immutable arguments while this would be perfectly valid. So "ref" is documenting that the function will modify this parameter. You can never expect anything else (or maybe curse the stupid developer that missed marking the parameter as const).
Jun 20 2023
next sibling parent reply GrimMaple <grimmaple95 gmail.com> writes:
On Tuesday, 20 June 2023 at 16:18:16 UTC, Dom DiSc wrote:
 This is what "ref" is for.
No, ref is to not pass arguments on stack. Though having three ways to do so isn't helping with clarifying what the function will actually do :)
 Hurray!
 I'm so glad this is not allowed. "in" means const. There is no 
 gain in "const const".
Only in D spec. `in` doesn't have to mean `const`, the language can be designed in a way to allow something like this: ```d void fn(in T1 param1, in out T2 param2); ```
 Sorry, but if a function takes a "ref" that it never modifies, 
 I would call this simply a bug. It prevents you from calling it 
 with const or immutable arguments while this would be perfectly 
 valid.
 So "ref" is documenting that the function will modify this 
 parameter. You can never expect anything else (or maybe curse 
 the stupid developer that missed marking the parameter as 
 const).
Again, only in D spec. However, if you want to be pedantic, `const ref Type` makes 0 sense, because all references are `const` already (you can't change the _reference_, you can change the _referenced object_). What you probably want to mean is `ref const(Type)` instead, making it a const reference to a const `Type`. I understand the idea behind using `in`, `out`, and `inout` to better explain what parameters actually do, but D's support for that is very poor. Yet, somehow, very complicated at the same time. Fun fact: this is compileable D code ```d void foo(out int a) { writeln(a); } ``` When it should error out with `"a" isn't assigned a value`. Instead, it defaults to `init` :)
Jun 20 2023
parent reply Dom DiSc <dominikus scherkl.de> writes:
On Tuesday, 20 June 2023 at 20:44:42 UTC, GrimMaple wrote:

 `const ref Type` makes 0 sense, because all references are 
 `const` already (you can't change the _reference_, you can 
 change the _referenced object_). What you probably want to mean 
 is `ref const(Type)` instead, making it a const reference to a 
 const `Type`.
Oops. This is really stupid. Then you are right, it should always be "ref const(T)". But I don't understand how "const ref" can mean something different in D, as references are NEVER writeable. This only uglyfies the language :-( So the nicer syntax is simply useless and confusing? If anything, I would propose to change that: "const ref T" should be identical to "ref const(T)"
Jun 21 2023
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 6/21/23 4:51 AM, Dom DiSc wrote:
 On Tuesday, 20 June 2023 at 20:44:42 UTC, GrimMaple wrote:
 
 `const ref Type` makes 0 sense, because all references are `const` 
 already (you can't change the _reference_, you can change the 
 _referenced object_). What you probably want to mean is `ref 
 const(Type)` instead, making it a const reference to a const `Type`.
Oops. This is really stupid. Then you are right, it should always be "ref const(T)".
`const` is both a type modifier, and a storage class. When used as a storage class, it means the type specified is attributed with the `const` type modifier. In certain contexts, it also can indicate that the variable should be stored in ROM. So `const ref Type` makes sense, the `const` means "apply the `const` type modifier to the stored type". So `const ref Type` is the same as `ref const Type` or `ref const(Type)`, the canonical form.
 So the nicer syntax is simply useless and confusing?
 If anything, I would propose to change that:
 "const ref T" should be identical to "ref const(T)"
It does mean this. -Steve
Jun 22 2023
parent Dom DiSc <dominikus scherkl.de> writes:
On Friday, 23 June 2023 at 02:24:07 UTC, Steven Schveighoffer 
wrote:
 `const` is both a type modifier, and a storage class. When used 
 as a storage class, it means the type specified is attributed 
 with the `const` type modifier. In certain contexts, it also 
 can indicate that the variable should be stored in ROM.

 So `const ref Type` makes sense, the `const` means "apply the 
 `const` type modifier to the stored type".

 So `const ref Type` is the same as `ref const Type` or `ref 
 const(Type)`, the canonical form.
Pew, ok. I was just about to change a LOT of my code... Glad I'm not as stupid as I thought.
Jun 22 2023
prev sibling parent reply Cecil Ward <cecil cecilward.com> writes:
On Tuesday, 20 June 2023 at 16:18:16 UTC, Dom DiSc wrote:
 Just to put it in clearer words:

 On Tuesday, 20 June 2023 at 15:01:17 UTC, Cecil Ward wrote:
 I would love to be able to document my arguments as in or out 
 but also as read-write
This is what "ref" is for.
 We already have "in". Good thing.

 However it has got mixed up with const so that you can’t 
 declare something as both.
Hurray! I'm so glad this is not allowed. "in" means const. There is no gain in "const const".
 However I hate using ref for input-output arguments as it 
 isn’t visible at the call site
This is true for all annotations.
 and a ref could be just ref-for-implementation
Sorry, but if a function takes a "ref" that it never modifies, I would call this simply a bug. It prevents you from calling it with const or immutable arguments while this would be perfectly valid. So "ref" is documenting that the function will modify this parameter. You can never expect anything else (or maybe curse the stupid developer that missed marking the parameter as const).
We seem to have very different approaches. I like the fact that const prevents me from modifying the argument inside the function. I use that a lot. I never use ref apart from by-ref-performance cases, although really the compiler should deal with that and split the passing strategies according to the size of the object in question. You’re wrong about the call site because I always then use pointers and an & is visible at the call site. And there’s not so much danger in a const pointer argument as there cannot be any pointer modification although it can be stored externally which is potentially bad. I’m not a C++ programmer and the first time I ever looked at it I looked at &-ref and screamed, it’s like var parameters in Pascal etc. C is just about all I known. So you can see I’m a dinosaur and am keeping it C-like by default, unless I can see a good reason not to. Even though there are so many things I am not too happy with in C now that I’ve seen D and am starting to feel my way around it.
Jun 20 2023
parent Cecil Ward <cecil cecilward.com> writes:
On Wednesday, 21 June 2023 at 01:37:56 UTC, Cecil Ward wrote:
 On Tuesday, 20 June 2023 at 16:18:16 UTC, Dom DiSc wrote:
 Just to put it in clearer words:

 On Tuesday, 20 June 2023 at 15:01:17 UTC, Cecil Ward wrote:
 I would love to be able to document my arguments as in or out 
 but also as read-write
This is what "ref" is for.
 We already have "in". Good thing.

 However it has got mixed up with const so that you can’t 
 declare something as both.
Hurray! I'm so glad this is not allowed. "in" means const. There is no gain in "const const".
 However I hate using ref for input-output arguments as it 
 isn’t visible at the call site
This is true for all annotations.
 and a ref could be just ref-for-implementation
Sorry, but if a function takes a "ref" that it never modifies, I would call this simply a bug. It prevents you from calling it with const or immutable arguments while this would be perfectly valid. So "ref" is documenting that the function will modify this parameter. You can never expect anything else (or maybe curse the stupid developer that missed marking the parameter as const).
We seem to have very different approaches. I like the fact that const prevents me from modifying the argument inside the function. I use that a lot. I never use ref apart from by-ref-performance cases, although really the compiler should deal with that and split the passing strategies according to the size of the object in question. You’re wrong about the call site because I always then use pointers and an & is visible at the call site. And there’s not so much danger in a const pointer argument as there cannot be any pointer modification although it can be stored externally which is potentially bad. I’m not a C++ programmer and the first time I ever looked at it I looked at &-ref and screamed, it’s like var parameters in Pascal etc. C is just about all I known. So you can see I’m a dinosaur and am keeping it C-like by default, unless I can see a good reason not to. Even though there are so many things I am not too happy with in C now that I’ve seen D and am starting to feel my way around it.
As you have all ready seen, I would like one small number of compiler internal behaviour changes regarding erroring things out, with no changes to existing programs, and one new keyword, which I now find we used to have anyway. So not a huge thing to ask for. What do others think about my proposal. Only reply if you want what I want, don’t tell me ‘how it works’. :-) as I already get most of that.
 Sorry, but if a function takes a "ref" that it never modifies, 
 I would call this simply a bug.
I couldn’t disagree with you more, however…
It prevents you from calling
 it with const or immutable arguments while this would be 
 perfectly valid.
This is what has bitten me in the past, and that is indeed as you say ‘the bug’. I wish it could be fixed in the compiler, so you can pass immutable objects by ref to any functions that solemnly promise not to write back to them. Thankyou for giving me further clue about why that evil might have been there.
Jun 20 2023
prev sibling parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 21/06/2023 3:01 AM, Cecil Ward wrote:
 I would love to be able to document my arguments
If you want a way to do it without compiler backed you can use UDA's: ```d void main() { func(2); } enum MyThing; void func( MyThing int x) { } ```
Jun 20 2023
parent Cecil Ward <cecil cecilward.com> writes:
On Wednesday, 21 June 2023 at 00:55:40 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
 On 21/06/2023 3:01 AM, Cecil Ward wrote:
 I would love to be able to document my arguments
If you want a way to do it without compiler backed you can use UDA's: ```d void main() { func(2); } enum MyThing; void func( MyThing int x) { } ```
Wow, I didn’t know that kind of tech was extensible like that. I really need the checking that the compiler does though, on in for example, making it const, and out presumably being either ref. (Or input-output passing of registers, seeing as having to have a pointer to a one machine word-sized value, say, that was in a register only one nanosec ago, is a bit mad. One hopes that the compilers might have a small size limit and switch to copy-by-ref only if args width exceeds that size.) That could give me a way of starting full documentation earlier though.
Jun 20 2023