Dot notation to Property Name on Null?

Here’s something I don’t understand: is it a bug?

If I run this code…
<code 4D>
$Name_t:=String(ds.Person.get(-1).First_Name)
</code 4D>
…and there is no Person(-1), then I get an error -10716: Object or collection expected.

But, If I run this code…
<code 4D>
C_OBJECT($Ent_ob)
$Ent_ob:=ds.Person.get(-1)
$Name_t:=String($Ent_ob.First_Name)
</code 4D>
…then I get the null string that I expect, with no error.

Is this not an inconsistency?

Also:

This also causes the error:
<code 4D>
$Name_t:=String((ds.Person.get(-1)).First_Name)
</code 4D>
(I just encapsulated a portion in an additional layer of parentheses)

But this does not cause the error:
<code 4D>
$Name_t:=String(OB_PassThrough (ds.Person.get(-1)).First_Name)
</code 4D>

where OB_PassThrough is a method with the following contents:
<code 4D>
C_OBJECT($1;$0)
$0:=$1
</code 4D>

It’s the way it’s designed…

Normally a property of NULL is an error.

We added some time ago a feature that you can do a king of “error ignore” in a specific environment. This was done to easy the usage of deep complex objects.
Again: objects.

like
$object.a.b.c.d

To use that, you need first to check $object.a, then $object.a.b, and so on, before you can access .d

While this is logical correct, it is boring.

So num($object.a.b.c.d) ignores any null inside the object chain and return 0 if one of those is null.

Again, this is strictly about objects.
If you use a command returning null it will still generate an error.

And that why your “trick” with OB_PassThrough works, you produce an object.

I supposed our reference would be the blog post “Don’t be afraid of undefined values”

https://blog.4d.com/object-notation-improvement-after-customer-feedback/

which explains that

“reading the property of a non-existing object…produces an undefined value.”

so the key seems to be, whether the dot-notation is applied to a “non-existing object” or not.

in both your good cases, you have a variable, or a parameter, that is declared as C_OBJECT.

in your fail case, you have an expression that evaluates as null.

maybe that’s the difference.

Thomas,

If you use a command returning null it will still generate an error.

I don’t find that to be true. For example: this code does NOT generate an error:
<code 4D>
C_OBJECT($MyNull_ob)
$Name_t:=String($MyNull_ob.First_Name)
</code 4D>

And also: In the example that I listed: my “OB_PassThrough” method simply assigns $0:=$1: so if $1 is null: $0 is null.

It’s inconsistent that one works and the other doesn’t.

I very much like that I can do $MyVar:=string($MyNullOb.a.b.c.d)
I very much wish I could do $MyVar:=string(ds.Person.get(-1).a.b.c.d)
So, in place, I guess I’ll have to do: $MyVar:=string(OB_PassThrough(ds.Person.get(-1)).a.b.c.d)

Miyako,

I think the post that you reference makes my case: it says

: BlogPost

In prior versions, reading the property of a non-existing object
generated an error and stopped the code execution.
Now in 4D v16 R5, it produces an undefined value.

It seems to me that this code
<code 4D>
$Name_t:=String((ds.Resident.get(-1)).First_Name)
</code 4D>
is producing a “a non-existing object”

I think it should work.

Hello Tony,

You can use a property just with an object, a collection or an undefined value.
In your example, the get() method returns Null because the entity doesn’t exist. So you can’t ask for a property of Null.

When you write:
C_OBJECT($Ent_ob)
$Ent_ob:=ds.Person.get(-1)
$Name_t:=String($Ent_ob.First_Name)

get(-1) returns Null and assigning an object to Null resets this object.
So when you write $Ent_ob:=ds.Person.get(-1) it is the same as CLEAR VARIABLE($Ent_ob). When you write $Ent_ob.First_Name,
$Ent_ob is an empty object and $Ent_ob.First_Name is undefined. So String($Ent_ob.First_Name) returns an empty string.

Fabrice,
I think you’re not understanding my point.

My point is: that I should be able to do (without runtime error):
$Name_t:=String(ds.Person.get(-1).First_Name)

But instead, I have to do this:
C_OBJECT($Ent_ob)
$Ent_ob:=ds.Person.get(-1)
$Name_t:=String($Ent_ob.First_Name)

: Tony RINGSMUTH

It seems to me that this code

$Name_t:=String((ds.Resident.get(-1)).First_Name)

is producing a “a non-existing object”

but, Null itself is not an object, so it does not qualify as “a non-existing object”.

it is not the same as assigning Null to an object (a variable or parameter that was declared as C_OBJECT).

Null != an object whose value/state is Null.

for instance, you can not pass Null as a “filler” parameter to a method that expects an object.