On Mon, Mar 20, 2023 at 12:49 AM rir <rir...@comcast.net> wrote:
>
> I did, and do, recognize the validity of the problem of 'undefine' not
> not aligning with '.defined'.

But do you understand the problem I was trying to communicate?

What you're writing suggests to me you know some other PL(s) that
have notions of truthiness and definedness that don't match Raku's,
and thus you don't recognize the problem, thinking it's just some trivial
name clash between `undefine` and `.defined`. It isn't. I'll have another
go at explaining. I apologize in advance if I again miss the mark, but I
still hope the penny will drop if I persevere. Wish us luck!

Let me first summarize relevant parts of Raku's design. These are not
going to change. They've been in place for 2 decades and work great.

In Raku, whether or not something is considered definite is determined
by an approach called "definiteness". An instance is definite. A type object
is indefinite. There are no other possibilities. This notion of definiteness
corresponds to the linguistic one that arises in many human languages.
Consider a tree. One either means a definite tree, that large oak at the
corner of the street, or an indefinite one, the idea of a tree. An instance,
that oak, is definite. The idea, the type object `Tree`, is indefinite.

In Raku, whether or not something is considered defined is determined
by an approach called "definedness". If a value is indefinite (eg the type
object `Tree`) then it is not defined. Always. By contrast, definite values
(instances) *are* defined by default, but there are exceptions. A `Failure`
instance is definite (because it's an instance, per the previous paragraph),
yet it is undefined (because it's an instance of a failure).

Finally, in Raku, whether or not something is considered true or false is
determined by an approach called "truthiness". If a value is undefined
then it is false. Always. By contrast, defined values are true by default
but there are exceptions. For example, the integer instance `0` is
definite (it's a particular integer), and defined, but is false (because it's
zero). As another example an array with zero elements is definite (it's
a particular array), and defined, but false (because it's empty).

This is how Raku works. We really aren't going to undo this 2 decade
old design.

----

Raku's current `undefine` only addresses truthiness, not definedness.

Here's the code in Rakudo (ignoring the proto):
```
multi sub undefine(Mu \x) is raw { x = Nil }
multi sub undefine(Array \x) is raw { x = Empty }
multi sub undefine(Hash \x) is raw { x = Empty }
```
The `Array` and `Hash` subs merely empty their argument. This leaves it
defined but false. As I said, `undefine` is about truthiness, not definedness.

For all other cases the argument is assigned `Nil`. If it's a `Scalar` with a
truthy `is default` value then the `undefine` isn't even going to manage
being about truthiness:
```
my $number is default(42) = 99;
say $number; # 99
undefine $number;
if $number { say $number } # 42
```
Do you really want all this insanity?

It's the wrong name. It does the wrong things. It needs to go.

> The docs indicate that being empty is the definition of undefinedness
> for non-scalar containers.

Wherever they say that they're wrong.

(Please consider filing a doc issue saying where you've seen such nonsense.)

> Keeping 'undefine' as a name of this action is beneficial because
> 'undefined' and 'defined' are mainstream terminology and so enable
> people to find and understand Raku's variant behavior.

I agree, provided `undefine` itself becomes a compile time error, ie we keep
`undefine` as the name of an action someone would expect if they come from
a PL that has an `undefine`, so we can make it an error that explains what to
do instead.

> A name like 'clear' would just be obscure--a great disadvantage.

I'm not happy with the name `clear` because what you really want to
know is what will happen to the argument after the function, whatever
it is called, has finished. Unfortunately, you can't be sure it will be clear,
as my above `is default(42)` example makes clear.

One could imagine renaming `undefine` to `default`:
```
my $number is default(42) = 99;
say $number; # 99
default $number;
if $number { say $number } # 42
my @array = [42,99];
default @array;
say @array; # []
```
But that's still not as good as:
```
my $number is default(42) = 99;
say $number; # 99
$number = 42;
if $number { say $number } # 42
```
or:
```
my $number is default(42) = 99;
say $number; # 99
$number = Nil;
if $number { say $number } # 42
```

----

The only case that's arguably awkward, or arguably fine though surprising,
is the one you began with, where you don't know if you're getting an `Array`
or `Hash` or something else.

But what is appropriate?

If you get an `Array` or `Hash`, it depends on what you want:

* Definiteness or definedness? If you want it indefinite (or undefined),
call `.WHAT` on the argument. (I note that neither the deprecated `undefine`
nor your replacement strawman proposed code deals with definedness.)

* Truthiness? Want to keep the same instance? Empty it. Want a fresh false
instance? Call `.new` on the argument. (I note that neither the deprecated
`undefine` nor your replacement strawman proposed code deals with the
issue of keeping the same instance or creating a fresh one.)

If you get any other value, it still depends on what you want but gets more
complicated:

* Definiteness or definedness? If you want it indefinite (or undefined),
call `.WHAT` on the argument. (I note that neither the deprecated `undefine`
nor your replacement strawman proposed code deals with definedness.)
(Note that this aspect is the same regardless of the type of the argument.)

* Truthiness? If it's a string, make it a null string. If it's a
number, make it zero.
And so on. (I note that neither the deprecated `undefine` nor your replacement
strawman proposed code considers these cases.)

--
love, ralph

Reply via email to