What about putting array.empty in object.d?

Jonathan M Davis jmdavisProg at gmx.com
Wed Mar 21 14:15:44 PDT 2012


On Wednesday, March 21, 2012 15:46:12 Steven Schveighoffer wrote:
> On Wed, 21 Mar 2012 14:33:58 -0400, Jonathan M Davis <jmdavisProg at gmx.com>
> 
> wrote:
> > On Wednesday, March 21, 2012 15:54:51 Daniel Murphy wrote:
> >> FWIW, I would rather see `if (array)` translated to `if (array.length)`
> >> and
> >> this become the recomended way to check if an array is empty. Wouldn't
> >> that
> >> remove the dependency on std.array for most of the cases?
> > 
> > The problem with checking whether length == 0 is that it's inefficient
> > for some
> > containers, so it's generally good practice to use empty rather than
> > length.
> 
> But we are specifically talking about arrays, not containers in general.
> Containers in general are not defined by the language.

I know that. Much point is that length == 0 is a bad thing to do in general, 
because it's ineffecient with some containers. The language itself is pretty 
much irrelevant as far as that goes. As such, I'd argue in pretty much _any_ 
language that using length == 0 instead of empty is _not_ a good habit to be 
in. Doing it with arrays will make it much more likely that you'll end up 
doing it with containers without thinking about it. On the other hand, if 
you're in the habit of _always_ using empty rather than length == 0, then you 
don't have the problem.

> > And while length == 0 is fine for arrays, it promotes bad habits in
> > general, so
> > I'm against it and think that code should pretty much always use empty
> > rather
> > than length == 0.
> 
> I think you may misunderstand the proposal. if(array) translating to
> if(array.length) is *only* for arrays, not for general types.

No. I understand just fine. My point is that doing length == 0 for _any_ type 
of container is bad, because it promotes bad habits and leads to inefficient 
code for containers where it _does_ matter. So, I'd argue that if you should 
always be using empty rather than length == 0 - even with arrays - which 
currently means that you're almost always importing std.array. Having empty in 
object.d certainly isn't necessary, but it mitigates the problem, because then 
you don't have to import it if all you care about is empty.

if(array) is a special case. If we want to change it to translate to 
if(array.length) then fine. That's all tied up in the insanity of an empty 
array and a null array being considered equal. But even if you want to use 
that syntax, it only mitigates the length == 0 vs empty issue for arrays 
rather than eliminating, because it only works directly in if statements and 
the like. The issue of choosing length == 0 vs empty still remains in many 
cases.

And actually, I'd personally shy away from the if(array) syntax regardless 
simply because of the inherent ambiguity. Even if the language clearly defines 
it, I believe that it's the sort of thing that programmers are likely to 
misunderstand - particularly since if(var) checks for null with all of the 
other reference types. Experienced D programmers will know, but since newbies 
probably won't I'd consider it a code smell.

I think that muddling null and empty was D's largest mistake with arrays and 
tend to think that any code that isn't explicit about it is asking for trouble 
if nothing else because the odds aren't low that the programmer did one thing 
when they meant another, because they didn't understand how null and empty 
arrays interact (e.g. arr == null is _always_ a bad sign IMHO).

> I don't see why defining empty in object.d is necessary for things that
> don't involve ranges at all.

It's not necessary, but it would be nice. empty isn't just a range thing. 
Containers in general use it (across many languages whether ranges are 
involved or not), and for the reasons that I've already given, I don't think 
that length == 0 should ever be used in code. So I'd argue that you should 
always be using empty, which means importing std.array all the time if empty 
isn't in object.d, even if you _aren't_ doing range-based operations.

Now, range-based operations are so common that you pretty much have to import 
std.range in most code anyway, so it really isn't all that much of a burden to 
have to import std.array or std.range to get at empty, but putting it in 
object.d definitely provides some benefit.

So, I'm not sure that I care all that much whether std.array.empty gets moved 
to object.d or not, but I'd strongly argue that code should import std.array 
and use it rather than checking length == 0 as long as empty is in std.array 
rather than in object.d. So, if putting empty in object.d promotes the use of 
empty over length == 0, I'm all for it.

- Jonathan M Davis


More information about the Digitalmars-d mailing list