January 23, 2005
"Lars Ivar Igesund" <larsivar@igesund.net> wrote in message news:cstu97$mqj$1@digitaldaemon.com...
> Matthew wrote:
>> "Walter" <newshound@digitalmars.com> wrote in message news:cspa3k$v95$2@digitaldaemon.com...
>>
>>>"nail" <nail_member@pathlink.com> wrote in message news:cson1b$5f6$1@digitaldaemon.com...
>>>
>>>>>PS.
>>>>>I still think that we need 'isnt' for '!=='
>>>>
>>>>In this case isnt must be :)
>>>>
>>>>What about future? Does === will become deprecated?
>>>
>>>Yes, use "is" from now on. The === turned out to be a problem distinguishing from == with some fonts.
>>
>>
>> So're we getting an 'isnt'?
>>
>>     if(!(x is null))
>>
>> is never going to be an attractive form
>
> I find this form quite appealing. So sue me.
>
> Lars Ivar Igesund
>
> PS Welcome back to the NG (Your book looks great, although I've just looked at the TOC :)

Thanks! <g>


January 23, 2005
On Fri, 21 Jan 2005 17:36:01 +0000 (UTC), <agent.smith@archvillain.com> wrote:

<snip>

> Another issue:  years ago I read something on a language newsgroup which really
> surprised me... that every Pascal 'with .. do' was a bug waiting to happen; but
> the author was right; what is even more scary is that the exact same issue
> exists in  every C++ member func; these inherit scopes in basically the same way
> as a with ..do.  It's actually worse in C++, because of class inheritance.
> This problem, which could result in bugs that take days to find, is
> commonly avoided by lexical conventions (e.g. starting member names with m_).
>
> Here's the problem in C++:
> ----
> static int table[] = {1,2,3};
>
> int MyClass::memberfunc(int i)
> {
> return table[i];
> }
> ---
> OK. Now imagine 'MyClass' is based on 'JoesClass', and next week Joe
> adds a member 'table' to his function. My memberfunc() function will now
> reference that member variable instead of the static local! If I'm really
> lucky, I'll get a compile error, if not, I'll get different runtime behaviour,
> despite the fact that I didn't touch my code, and Joe's change was done in
> such a way as not to change the existing class interface (other than by
> adding this name...) This could take ages to figure out. The reason
> this doesn't happen much is because most variable naming conventions
> avoid it (e.g m_); but I suspect few programmers realize that this can happen.
> I only realized recently that the Pascal problem applies to C++ too.
>
> This can be avoided, of course, by putting :: in front of table, but that's
> a lot of ::'s to use. Some languages (e.g. Python) require explicit this->,
> (or self.) which is also rather a pain, but at least avoids this problem.
>
> Is there is a similar issue in D?

Yes.

# static int table[] = [1,2,3];
#
# class A {
# 	//adding this line causes output of '4'
# 	//static int table[] = [4,5,6];
# }
#
# class B : A {
# 	int test(int x) { return table[x]; }
# }
#
# void main() {
# 	B b = new B();
# 	int x = 0;
#
# 	//outputs '1' unless above line is un-commented	
# 	printf("table[%d] = %d\n",x,b.test(x));
# }

> Fundamentally, the problem is that
> a name introduced into a distant scope (inherited class) can hide a variable
> in a scope which is in some sense much closer (file scope of the function);

The key phrase being "in some sense". I believe, either could be argued to be 'closer'. eg. the external is closer as it's in the same file. the parent class is closer to the child than external things are.

> it can be argued that the derived class and the file scope are under control
> of the author of the derived class, whereas the base class is not; and therefore
> this should not work this way.

Unfortunately we cannot "have our cake and eat it too", if classes did not inherit there would be little point in them. Fortunately I have a reasonably nice solution (depends on your opinion I suppose)

The way I see it:

1. Either 'table' is part of your class and should thus be included in it eg.

# class B : A {
#	static int table[] = [1,2,3];
# 	int test(int x) { return table[x]; }
# }

2. 'table' is some data from an external source i.e. lib.foobar and you should refer to it by it's full name, now, I agree it's somewhat ugly to have to say:

# class B : A {
# 	int test(int x) { return lib.foobar.table[x]; }
# }

if you have to use it in several places, so.. what about:

# class B : A {
#	alias table lib.foobar.table;
# 	int test(int x) { return table[x]; }
# }

> Maybe it's even more dangerous, somehow,
> to insert the file scope between the base class and derived class.

That at least increases the distance in terms of seeing the class and it's parent at the same time, so would make it harder to spot the bug.

> In any case, it seems to me that this is a detectable case of ambiguity, and it's not unreasonable to flag it as such, and require the :: to be used.

The way name resolution works IIRC is to start in the current scope and keep stepping up till it finds a name match, then it does implicit conversions to make the type match.

So, once the parent class definition has been added, there is no ambiguity (according to the name resolution system).

We could force people to refer to global variables by their full name (allowing aliasing as I have shown)

> The problem will also be avoided if Joe's member 'table' is private. It
> might not compile, but that's better than compiling with the wrong meaning.

Given the name resolution rules I'd expect an error.

> I apologize for not stating this in D terms, and I apologize profusely if
> this is discussed in the D docs somewhere, but I haven't had time to read
> it all yet... will do so before further ramblings..
> I did see just now that there is a with(){ } in D, which may suffer from the
> same problem, but this time accidentally hiding local vars instead of
> file-scope? This is more dangerous, if only because naming conventions are much
> less likely to protect you.

It seems "with" does have the same set of problems.

It seems to me that there are 2 solutions to this problem:

1. change name resolution to continue searching for a match after finding one, allowing it to highlight the ambiguity with an error, which would in some (many?) cases cause...

2. require the complete explicit specification of everything.

IIRC C# uses 2 above?

Which itself causes more typing for you and I, larger source files, slower parsing/compile times, etc. So, are the benefits worth the costs? As with everything it depends where you want to draw the line.

Regan
January 24, 2005
>>>    if(!(x is null))
>>>
>>>is never going to be an attractive form
>>
>>Until there are booleans in D, you can use:
>>
>>if(x)
> 
> I'm afraid I never write a non-boolean conditional
> (sub-)expression, so you won't catch me doing that. ;)

IMO if(x) should be made the official form of this idiom, in D.

And documented as such.

Every language has its preferred idioms, and every idiom can be attacked as unobvious, dangerous, etc. But having these idioms is what makes the language more fluent and usable.

The standard idioms make source code much more readable.

I understand that C or C++ users may feel uncomfortable with it. Heck, in the old days nothing forced the C compiler writer to use the all-zeros bit pattern to represent the null pointer. (Anybody wanna flame check it out first.)

I seem to remember that in D it is guaranteed that a null pointer is considered false in boolean contexts, but I couldn't find it now. And it seemed to be written in stone. Therefore, in D if(x) will stay valid.
January 24, 2005
>"Lars Ivar Igesund" <larsivar@igesund.net> wrote in message news:cstu97$mqj$1@digitaldaemon.com...
>> Matthew wrote:
>>> So're we getting an 'isnt'?
>>>
>>>     if(!(x is null))
>>>
>>> is never going to be an attractive form
>>
>> I find this form quite appealing. So sue me.

I've never liked this in any language,
not just because of the two almost adjacent () (which tend
to bury the vital "!" ), but because it's a double negative.
'x is null' is a negative; the 'if' is
followed by something you only do with a valid 'x'. What
you are conceptually saying is: "if x isn't not really there,
then do this stuff with it". For such a very common operation, why
should a negative be needed? Why not something which reads as
"if x is there, then ..."

So, in C, I prefer " if (ptr) { ... }". Some folks
don't like this at all, because of the implicit conversion from
pointer to bool. I can see that when p is a complex expression,
but for a simple variable, avoiding a double negative overrides this, IMHO.

The problem still exists if you bury the ! in the if (e.g. 'unless'
in perl). How about eliminating both negatives by adding an explicit
conversion from pointer to boolean.
i.e. instead of

if( !(x is null))

or

if(  x isnt null ) // worse than before, IMHO


how about

if( x.valid )   // new property of pointers

or

if( isvalid(x))  // already possible by defining isvalid, no?

if( cast(bit)x ) // kind of clumsy.










January 24, 2005
Georg Wrede wrote:

> IMO if(x) should be made the official form of this idiom, in D.
[...]
> I understand that C or C++ users may feel uncomfortable with it. Heck, in the old days nothing forced the C compiler writer to use the all-zeros bit pattern to represent the null pointer. (Anybody wanna flame check it out first.)

Old-school C or C++ users feel right at home with it,
since that's where it comes from. Java users do not,
or people from type-fascist languages such as Ada...


> I seem to remember that in D it is guaranteed that a null pointer is considered false in boolean contexts, but I couldn't find it now. And it seemed to be written in stone. Therefore, in D if(x) will stay valid.

The current D specification is not very clear on this. :-(


http://www.digitalmars.com/d/statement.html#if:
> Expression is evaluated and must have a type that can be converted to
> a boolean. If it's true the if statement is transferred to, else the
> else statement is transferred to.
The only problem is that *there is no boolean*...
(other parts of the specification talk about "bool")

But http://www.digitalmars.com/d/expression.html:
> true, false
> These are of type bit and resolve to values 1 and 0, respectively.
So bit is the boolean type, and conversions a bit shady.


But in practice, D follows the C and C++ tradition:
zero and null are false and non-zero/null are true:

> void main()
> {
>   assert(true);
>   assert(!false);
>   assert(new Object());
>   assert(!null);
>   assert(1);
>   assert(!0);
> }

In Java, for instance, the last four are semantic errors:
> The type of this expression, "java.lang.Object", is not "boolean".
> The type of this expression, "null", is not "boolean".
> The type of this expression, "int", is not "boolean".
> The type of this expression, "int", is not "boolean".


However, in D you still cannot copy such values without a cast:

>   bit a,b,c;
>   Object o = new Object();
>   int i = 2;
> 
>   a = true;
>   b = o;
>   c = i;

Gives errors:

> cannot implicitly convert expression o of type Object to bit
> cannot implicitly convert expression i of type int to bit

If the proper "cast(bit)" is inserted, all three are "true".


Which means that "bool/boolean conversion" refers to the operation
of comparing integers with 0, and pointers/references with null...

This should probably be mentioned explicitly in the D specification.
(probably along with "some think this automatic conversion is a bug")

--anders
January 24, 2005
agent.smith@archvillain.com wrote:

> i.e. instead of
> 
> if( !(x is null)) 
> 
> or
> 
> if(  x isnt null ) // worse than before, IMHO
> 
> 
> how about
> 
> if( x.valid )   // new property of pointers

What if x is null, though ? Does null have any properties ?

> or
> 
> if( isvalid(x))  // already possible by defining isvalid, no?

Yes, although specifying the argument type could be tricky...

> if( cast(bit)x ) // kind of clumsy.

You can say that again... "cast(bool)" is not better at all.



No, the current solution that D already has is the shortest by far:

if (x)

Although I don't think "assert (pointer isnot null);" is all bad ?
Not very much better than the old "(pointer !== null)" one, though

--anders
January 24, 2005
In article <ct3fi4$1s4g$2@digitaldaemon.com>, =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= says...
>
>agent.smith@archvillain.com wrote:

>> how about
>> 
>> if( x.valid )   // new property of pointers
>
>What if x is null, though ? Does null have any properties ?'

variable x has properties, since it has a type.
Nullness or non-nullness is a run-time condition. The existence
of the property is determined at compile-time; the value
is determined at run-time.

>
>> or
>> 
>> if( isvalid(x))  // already possible by defining isvalid, no?
>
>Yes, although specifying the argument type could be tricky...

I had 'void *' in mind. Don't know enough D to be sure.

>No, the current solution that D already has is the shortest by far:
>
>if (x)
>
>--anders

yup.


January 24, 2005
In article <ct3f7c$1s4g$1@digitaldaemon.com>, =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= says...
>
>Georg Wrede wrote:
>
>> IMO if(x) should be made the official form of this idiom, in D.
>[...]
>> I understand that C or C++ users may feel uncomfortable with it. Heck, in the old days nothing forced the C compiler writer to use the all-zeros bit pattern to represent the null pointer. (Anybody wanna flame check it out first.)
>
>Old-school C or C++ users feel right at home with it,
>since that's where it comes from. Java users do not,
>or people from type-fascist languages such as Ada...
>
In C, it doesn't matter whether all-zero pattern is used. The compiler
can use something else for null ptr, but then when a pointer appears in
a boolean context, the code has to test for that pattern. Also, when
you assign constant int 0 to a pointer, it has to convert to that. I.e.
"p=0" would work on such a machine, but "int x=0; p=(char*)x" would not.
And "p=1" is an error even if the null pattern is binary 1.
Likewise, when comparing a pointer to a int constant, the int must be zero
and you are really comparing to null. So all of this is handled at the
semantic level.
FWIW, I don't know of a machine that doesn't use 0. I did use -1 once on
a DSP for a link-list endpoint, because testing the MSB of an address
reg was much cheaper than comparing the whole thing to zero (and I could
blow off 1/2 the address space) but that was in assembler.





January 24, 2005
agent.smith@archvillain.com wrote:

> I've never liked this in any language,
> not just because of the two almost adjacent () (which tend
> to bury the vital "!" ), but because it's a double negative. 'x is null' is a negative; the 'if' is

Would you consider if(x==0) a negative?
January 24, 2005
"Georg Wrede" <georg.wrede@nospam.org> wrote in message news:41F52972.4040208@nospam.org...
>>>>    if(!(x is null))
>>>>
>>>>is never going to be an attractive form
>>>
>>>Until there are booleans in D, you can use:
>>>
>>>if(x)
>>
>> I'm afraid I never write a non-boolean conditional
> > (sub-)expression, so you won't catch me doing that. ;)
>
> IMO if(x) should be made the official form of this idiom, in D.
>
> And documented as such.
>
> Every language has its preferred idioms, and every idiom can be attacked as unobvious, dangerous, etc. But having these idioms is what makes the language more fluent and usable.
>
> The standard idioms make source code much more readable.

That's nice, and in almost all other ways I've fallen into line with the D way of things - no more whinges about boolean, using dCaseMethods, etc. etc. But there's no way I'm writing non-boolean conditional (sub-)expressions. Sorry.

>
> I understand that C or C++ users may feel uncomfortable with it. Heck, in the old days nothing forced the C compiler writer to use the all-zeros bit pattern to represent the null pointer. (Anybody wanna flame check it out first.)
>
> I seem to remember that in D it is guaranteed that a null pointer is considered false in boolean contexts, but I couldn't find it now. And it seemed to be written in stone. Therefore, in D if(x) will stay valid.