Thread overview | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
August 08, 2017 Express "Class argument may not be null" ? | ||||
---|---|---|---|---|
| ||||
Hi all, How would you express the function interface intent that a reference to a class may not be null? For a function "void foo(Klass)", calling "foo(null)" is valid. How do I express that that is invalid? (let's leave erroring with a compile error aside for now) Something equivalent to C++'s pass by reference: "void foo(Klass&)". (note: I mean D classes, for structs "ref" works) Thanks, Johan |
August 08, 2017 Re: Express "Class argument may not be null" ? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Johan Engelen | On 08/08/2017 08:34 PM, Johan Engelen wrote: > How would you express the function interface intent that a reference to a class may not be null? > For a function "void foo(Klass)", calling "foo(null)" is valid. How do I express that that is invalid? (let's leave erroring with a compile error aside for now) > > Something equivalent to C++'s pass by reference: "void foo(Klass&)". A contract might be the best you can do: ---- void foo(Klass k) in { assert(k !is null); } body {} ---- Or throw an exception. > (note: I mean D classes, for structs "ref" works) But you can pass null in a ref parameter: ---- void f(ref int x) @safe {} void main() @safe { int* p = null; f(*p); } ---- |
August 08, 2017 Re: Express "Class argument may not be null" ? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Johan Engelen | On 8/8/17 2:34 PM, Johan Engelen wrote:
> Hi all,
> How would you express the function interface intent that a reference to a class may not be null?
> For a function "void foo(Klass)", calling "foo(null)" is valid. How do I express that that is invalid? (let's leave erroring with a compile error aside for now)
There isn't a way to do this in the type itself.
One can always create a null class instance via:
MyObj obj;
There is no way to disallow this somehow in the definition of MyObj. With structs, you can @disable this(), and it's still possible but harder to do so.
I would say, however, that if you wanted to express the *intent*, even without a compile-time error, you could use a contract:
void foo(Klass k) in {assert(k !is null);};
Since the contract is part of the signature, this should be symantically what you want.
However, this has to be done on every function that would accept a Klass, there's no way to bake it into the type itself.
-Steve
|
August 08, 2017 Re: Express "Class argument may not be null" ? | ||||
---|---|---|---|---|
| ||||
Posted in reply to ag0aep6g | On 8/8/17 2:56 PM, ag0aep6g wrote: > On 08/08/2017 08:34 PM, Johan Engelen wrote: >> How would you express the function interface intent that a reference to a class may not be null? >> For a function "void foo(Klass)", calling "foo(null)" is valid. How do I express that that is invalid? (let's leave erroring with a compile error aside for now) >> >> Something equivalent to C++'s pass by reference: "void foo(Klass&)". [snip] > > But you can pass null in a ref parameter: > > ---- > void f(ref int x) @safe {} > void main() @safe > { > int* p = null; > f(*p); > } > ---- Note that C++ also can do this, so I'm not sure the & is accomplishing the correct goal: void foo(Klass&); int main() { Klass *k = NULL; foo(*k); } However, the in contract does actually enforce the requirement. -Steve |
August 08, 2017 Re: Express "Class argument may not be null" ? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Tuesday, 8 August 2017 at 18:57:48 UTC, Steven Schveighoffer wrote: > On 8/8/17 2:34 PM, Johan Engelen wrote: >> Hi all, >> How would you express the function interface intent that a reference to a class may not be null? >> For a function "void foo(Klass)", calling "foo(null)" is valid. How do I express that that is invalid? (let's leave erroring with a compile error aside for now) > > There isn't a way to do this in the type itself. > > One can always create a null class instance via: > > MyObj obj; > > There is no way to disallow this somehow in the definition of MyObj. With structs, you can @disable this(), and it's still possible but harder to do so. Ok thanks, so this could be a reason for not being allowed to express the non-null-ness. (I still haven't found peace with the absence of an explicit * for classes) > I would say, however, that if you wanted to express the *intent*, even without a compile-time error, you could use a contract: > > void foo(Klass k) in {assert(k !is null);}; Thanks. I regret leaving compile-time errors out, because in that case adding it to the function documentation would suffice. (Btw: "Error: function foo in and out contracts require function body". But who uses .di files anyway. ;-) Cheers, Johan |
August 08, 2017 Re: Express "Class argument may not be null" ? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Tuesday, 8 August 2017 at 19:38:19 UTC, Steven Schveighoffer wrote: > > Note that C++ also can do this, so I'm not sure the & is accomplishing the correct goal: > > void foo(Klass&); > > int main() > { > Klass *k = NULL; > foo(*k); > } In C++, it is clear that the _caller_ is doing the dereferencing, and the dereference is also explicit. > However, the in contract does actually enforce the requirement. And adds null pointer checks even when clearly not needed. - Johan |
August 08, 2017 Re: Express "Class argument may not be null" ? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On 2017-08-08 12:38 PM, Steven Schveighoffer wrote:
> On 8/8/17 2:56 PM, ag0aep6g wrote:
>> On 08/08/2017 08:34 PM, Johan Engelen wrote:
>>> How would you express the function interface intent that a reference to a class may not be null?
>>> For a function "void foo(Klass)", calling "foo(null)" is valid. How do I express that that is invalid? (let's leave erroring with a compile error aside for now)
>>>
>>> Something equivalent to C++'s pass by reference: "void foo(Klass&)".
> [snip]
>>
>> But you can pass null in a ref parameter:
>>
>> ----
>> void f(ref int x) @safe {}
>> void main() @safe
>> {
>> int* p = null;
>> f(*p);
>> }
>> ----
>
> Note that C++ also can do this, so I'm not sure the & is accomplishing the correct goal:
>
> void foo(Klass&);
>
> int main()
> {
> Klass *k = NULL;
> foo(*k);
> }
>
> However, the in contract does actually enforce the requirement.
To be fair: it cannot be done in C++ without first invoking Undefined Behaviour (such as dereferencing a nullptr).
|
August 08, 2017 Re: Express "Class argument may not be null" ? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Johan Engelen | I was about to say "use NotNull" but there still isn't one in std.typecons. ugh. But it is just a wrapper type that checks null in the contracts too, so you can do it at the function itself. |
August 09, 2017 Re: Express "Class argument may not be null" ? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Johan Engelen | On 8/8/17 3:59 PM, Johan Engelen wrote: > On Tuesday, 8 August 2017 at 19:38:19 UTC, Steven Schveighoffer wrote: >> >> Note that C++ also can do this, so I'm not sure the & is accomplishing the correct goal: >> >> void foo(Klass&); >> >> int main() >> { >> Klass *k = NULL; >> foo(*k); >> } > > In C++, it is clear that the _caller_ is doing the dereferencing, and the dereference is also explicit. In fact it's not doing any dereferencing. It's just under the hood passing a pointer. >> However, the in contract does actually enforce the requirement. > > And adds null pointer checks even when clearly not needed. Clearly not needed? I thought the point was to ensure the reference is not null? -Steve |
August 09, 2017 Re: Express "Class argument may not be null" ? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andre Kostur | On 8/8/17 4:00 PM, Andre Kostur wrote:
> On 2017-08-08 12:38 PM, Steven Schveighoffer wrote:
>> On 8/8/17 2:56 PM, ag0aep6g wrote:
>>> On 08/08/2017 08:34 PM, Johan Engelen wrote:
>>>> How would you express the function interface intent that a reference to a class may not be null?
>>>> For a function "void foo(Klass)", calling "foo(null)" is valid. How do I express that that is invalid? (let's leave erroring with a compile error aside for now)
>>>>
>>>> Something equivalent to C++'s pass by reference: "void foo(Klass&)".
>> [snip]
>>>
>>> But you can pass null in a ref parameter:
>>>
>>> ----
>>> void f(ref int x) @safe {}
>>> void main() @safe
>>> {
>>> int* p = null;
>>> f(*p);
>>> }
>>> ----
>>
>> Note that C++ also can do this, so I'm not sure the & is accomplishing the correct goal:
>>
>> void foo(Klass&);
>>
>> int main()
>> {
>> Klass *k = NULL;
>> foo(*k);
>> }
>>
>> However, the in contract does actually enforce the requirement.
>
> To be fair: it cannot be done in C++ without first invoking Undefined Behaviour (such as dereferencing a nullptr).
If your "insurance" that null pointers aren't passed is the threat of undefined behavior, then it leaves a lot to be desired.
It's possible, and does happen. The "just don't write bugs" approach doesn't scale.
-Steve
|
Copyright © 1999-2021 by the D Language Foundation