Excerpts from the mail message of Mark Jefferys:
)
) ["@x= (undef,undef)" is false.]
)
) Well, this can't be considered a bug, since it's intentional (maybe a
) documentation bug---I was really lax on that obligation). It might be
) a bad idea, although I don't really like any of the solutions:
Indeed, a complicated issue. I've rolled this around at many
angles...
I think it is clear that often you don't want undefs created as
place holders and often you don't want trailing undefs stripped.
Perl puts practicality before rigid consistancy so creating and
stripping undefs is common, but not universal. I think the best
solution is to allow the user to select from both types of
behavior, so long as it can be done reasonably. For example,
using "-1" in "split(/re/,$str,-1)" lets us prevent the default
stripping of trailing nulls.
I'm sure we don't want to change
@arr[@sub] and @hash{@sub}
so that they no longer return ("create") undefs for out-of-bounds
subscripts and non-existant keys. But I think being able to
request exactly that behavior could be generally useful. If
we allow this behavior for anonymous array slices as well, then
that can be used for the
if( @arr= (getpwent)[0,2] )
case and thus removes any motivation for having
"@x= (undef,undef)" considered false
(at least I don't see any other motivation).
How about:
@arr[@sub] for map { $arr[$_] } @sub
@arr([@sub]) for map { $_ < $[ || $#arr < $_ ? () : $arr[$_] } @sub
@hash{@sub} for map { $arr{$_} } @sub
@hash({@sub}) for map { $_ in keys(%hash) ? $hash{$_} : () } @sub
where "$_ in keys(%hash)" is pseudo Perl for whether hv_fetch()
returned 0. [.I don't think this adds ambiguity to the parsing,
but I certainly could be wrong.]
That is, @arr[@sub] and @hash{@sub}, stay the same. @arr([@sub])
does not "create" undefs as place holders for out-of-bounds
elements. @hash({@sub}) does not "create" undefs as place holders
for non-existant keys.
So we would now have to do:
if( @arr= (getpwent)([0,2]) )
^ ^
since "if( @arr= (getpwent)[0,2] )" never worked in perl4 anyway.
I'd also like a way to tell if a key is present in a hash, ie.
distinquish between hv_fetch() returning 0 vs. &(&sv_undef). For
most tied hashes, it would be the same as defined($hash{$key}),
but defining a non-default EXISTS() would allow a difference. So
using @tied_hash({@sub}) would cause EXISTS() to be called if
FETCH() returned undef [.I probably wouldn't change hv_fetch() but
instead change a few callers of hv_fetch() and add a caller].
Perhaps a new boolean: "$key in %hash" or "in(%hash,$key)".
Perhaps "keys(%hash,@keys)" could return the elements of @keys
that are keys of %hash: "map { $_ in %hash ? $_ : () } @keys".
But, in case you hate @arr([@sub]) and can't suggest a better
way to suppress undef place holders, here are my thoughts on
the previously proposed solutions:
) 1. Document the real behavior. Suggest using
) if ((@arr = func()), @arr) ...
) when a list of undefs should be true.
Kinda yuck but no worse than a few other rare cases in Perl.
Probably not possible in the face of the powerful special-interest
lobby from the DB users. :)
) 2. Make list-assignments return undef for zero objects assigned,
) and SV_NO for undef-only assignments. This allows:
) if (defined(@arr = func())) ...
This doesn't allow you, in (func())[0,2], to distinguish whether
func() returned () or (undef,"foo",undef,"bar").
It also means defined() is required above but if you try to
make a habit of using defined() you'll get bit because
while( defined( @arr= (getpwent)[0,2] ) ) {
will never end.
) 3. Make list-assignments normal, but have list-slices cut off
) trailing undefs, so
) (getpwent)[0,2]
) returns an empty list.
) A. This will cause code which relies on list-slices
) returning a fixed number of items to break. Sub calls
) are a likely source of problems:
) func1((func2())[1,3], ++$cnt);
) # Expects $cnt in 3rd place, not last.
) B. If any of the elements sliced is magic, we either have to
) get its value, which wastes time and can cause problems,
) or *not* get its value, which can fail.
I don't understand this last one (B).
) 4. Same as #3, except only eliminate undefs if you can eliminate
) all of them. Slightly reduces the problem with #A, does nothing
) for #B.
) 5. Same as #3, except cut off trailing *out-of-bound* references in
) list-slices. More likely to do what you want with #A, and fixes
) #B.
) 6. Combine #4 and #5. Same comments as #5.
The problem of documenting these properly makes me very wary of them.
) 7. Make a list-slice of an empty list be empty. This is an example
) of minimal intervention: make sure empty lists stay empty, and
) thus false, but otherwise acts normally. This would be somewhat
) easier to implement for tied arrays (and hashes).
This raises the problem of (A) again.
) 8. Make array assignments of slices magical, returning false if the
) original list was empty (or something). A really do-what-I-want
) solution.
But will still surprise people with
while( @ids= (getpwent)[2,3] ) {
if( $ids[0] == $uid && $ids[1] == $gid ) {
last;
}
}
if( @ids ) {
# We found a match!
}
because we'll always "find a match".
If it can be implemented relatively easilly, I'd vote for this.
[.Why do I keep thinking we need a new value, NoneSuch, which is
used for things that have never been set (such as out-of-bounds
elements)? exists() would be to NoneSuch as defined() is to
sv_undef. There would be no _direct_ way to set anything to
NoneSuch ("$#arr=5" indirectly sets "$arr[6]" to NoneSuch,
"delete($hash{key})" indirectly sets "$hash{key}" to NoneSuch).
In an assignment, NoneSuch is always transformed to sv_undef.
Would this help the problem of sv_undef causing too many "Use
of uninitialized value" warnings?]
--
Tye McQueen tye@metronet.com || tye@doober.usu.edu
Nothing is obvious unless you are overlooking something
http://www.metronet.com/~tye/ (scripts, links, nothing fancy)
)
) ["@x= (undef,undef)" is false.]
)
) Well, this can't be considered a bug, since it's intentional (maybe a
) documentation bug---I was really lax on that obligation). It might be
) a bad idea, although I don't really like any of the solutions:
Indeed, a complicated issue. I've rolled this around at many
angles...
I think it is clear that often you don't want undefs created as
place holders and often you don't want trailing undefs stripped.
Perl puts practicality before rigid consistancy so creating and
stripping undefs is common, but not universal. I think the best
solution is to allow the user to select from both types of
behavior, so long as it can be done reasonably. For example,
using "-1" in "split(/re/,$str,-1)" lets us prevent the default
stripping of trailing nulls.
I'm sure we don't want to change
@arr[@sub] and @hash{@sub}
so that they no longer return ("create") undefs for out-of-bounds
subscripts and non-existant keys. But I think being able to
request exactly that behavior could be generally useful. If
we allow this behavior for anonymous array slices as well, then
that can be used for the
if( @arr= (getpwent)[0,2] )
case and thus removes any motivation for having
"@x= (undef,undef)" considered false
(at least I don't see any other motivation).
How about:
@arr[@sub] for map { $arr[$_] } @sub
@arr([@sub]) for map { $_ < $[ || $#arr < $_ ? () : $arr[$_] } @sub
@hash{@sub} for map { $arr{$_} } @sub
@hash({@sub}) for map { $_ in keys(%hash) ? $hash{$_} : () } @sub
where "$_ in keys(%hash)" is pseudo Perl for whether hv_fetch()
returned 0. [.I don't think this adds ambiguity to the parsing,
but I certainly could be wrong.]
That is, @arr[@sub] and @hash{@sub}, stay the same. @arr([@sub])
does not "create" undefs as place holders for out-of-bounds
elements. @hash({@sub}) does not "create" undefs as place holders
for non-existant keys.
So we would now have to do:
if( @arr= (getpwent)([0,2]) )
^ ^
since "if( @arr= (getpwent)[0,2] )" never worked in perl4 anyway.
I'd also like a way to tell if a key is present in a hash, ie.
distinquish between hv_fetch() returning 0 vs. &(&sv_undef). For
most tied hashes, it would be the same as defined($hash{$key}),
but defining a non-default EXISTS() would allow a difference. So
using @tied_hash({@sub}) would cause EXISTS() to be called if
FETCH() returned undef [.I probably wouldn't change hv_fetch() but
instead change a few callers of hv_fetch() and add a caller].
Perhaps a new boolean: "$key in %hash" or "in(%hash,$key)".
Perhaps "keys(%hash,@keys)" could return the elements of @keys
that are keys of %hash: "map { $_ in %hash ? $_ : () } @keys".
But, in case you hate @arr([@sub]) and can't suggest a better
way to suppress undef place holders, here are my thoughts on
the previously proposed solutions:
) 1. Document the real behavior. Suggest using
) if ((@arr = func()), @arr) ...
) when a list of undefs should be true.
Kinda yuck but no worse than a few other rare cases in Perl.
Probably not possible in the face of the powerful special-interest
lobby from the DB users. :)
) 2. Make list-assignments return undef for zero objects assigned,
) and SV_NO for undef-only assignments. This allows:
) if (defined(@arr = func())) ...
This doesn't allow you, in (func())[0,2], to distinguish whether
func() returned () or (undef,"foo",undef,"bar").
It also means defined() is required above but if you try to
make a habit of using defined() you'll get bit because
while( defined( @arr= (getpwent)[0,2] ) ) {
will never end.
) 3. Make list-assignments normal, but have list-slices cut off
) trailing undefs, so
) (getpwent)[0,2]
) returns an empty list.
) A. This will cause code which relies on list-slices
) returning a fixed number of items to break. Sub calls
) are a likely source of problems:
) func1((func2())[1,3], ++$cnt);
) # Expects $cnt in 3rd place, not last.
) B. If any of the elements sliced is magic, we either have to
) get its value, which wastes time and can cause problems,
) or *not* get its value, which can fail.
I don't understand this last one (B).
) 4. Same as #3, except only eliminate undefs if you can eliminate
) all of them. Slightly reduces the problem with #A, does nothing
) for #B.
) 5. Same as #3, except cut off trailing *out-of-bound* references in
) list-slices. More likely to do what you want with #A, and fixes
) #B.
) 6. Combine #4 and #5. Same comments as #5.
The problem of documenting these properly makes me very wary of them.
) 7. Make a list-slice of an empty list be empty. This is an example
) of minimal intervention: make sure empty lists stay empty, and
) thus false, but otherwise acts normally. This would be somewhat
) easier to implement for tied arrays (and hashes).
This raises the problem of (A) again.
) 8. Make array assignments of slices magical, returning false if the
) original list was empty (or something). A really do-what-I-want
) solution.
But will still surprise people with
while( @ids= (getpwent)[2,3] ) {
if( $ids[0] == $uid && $ids[1] == $gid ) {
last;
}
}
if( @ids ) {
# We found a match!
}
because we'll always "find a match".
If it can be implemented relatively easilly, I'd vote for this.
[.Why do I keep thinking we need a new value, NoneSuch, which is
used for things that have never been set (such as out-of-bounds
elements)? exists() would be to NoneSuch as defined() is to
sv_undef. There would be no _direct_ way to set anything to
NoneSuch ("$#arr=5" indirectly sets "$arr[6]" to NoneSuch,
"delete($hash{key})" indirectly sets "$hash{key}" to NoneSuch).
In an assignment, NoneSuch is always transformed to sv_undef.
Would this help the problem of sv_undef causing too many "Use
of uninitialized value" warnings?]
--
Tye McQueen tye@metronet.com || tye@doober.usu.edu
Nothing is obvious unless you are overlooking something
http://www.metronet.com/~tye/ (scripts, links, nothing fancy)