November 24, 2013
On Sunday, 24 November 2013 at 14:16:39 UTC, bearophile wrote:
> Maxim Fomin:
>
>> This is neither bug not a terribale feature.
>
> I think the implicit question of ilya-stromberg was: how much bug-prone is this language feature?

Yes, exactly. I personally was VERY surprised. My code example from real life:

class Foo
{
}

class Bar
{
	Foo f;
	
	void bar()
	{
		//variable was wrongly commented here
		//bool f = true;
		
		if(f)
		{
			//Oops!
		}
	}
}
November 24, 2013
On Sunday, 24 November 2013 at 14:24:09 UTC, ilya-stromberg wrote:
> On Sunday, 24 November 2013 at 14:17:50 UTC, Dicebot wrote:
>> Not exactly. It is all about "if" condition. AFAIK, D defines that condition `if(X)` get re-written to `if(cast(bool)X)` before semantic pass. So it is kind of implicit explicit conversion :)
>
> Not exactly.
>
> Code:
>
> bool b = f;
>
> DMD output:
>
> Error: cannot implicitly convert expression (f) of type Foo to bool
>
>
> But code:
>
> bool b = !f;
>
> compiles.

Because '!' operator provides boolean context. It is written in the spec, although not explicitly. By the way, the same happens with objects with pretty many types (except structs which do not provide necessary operator overloads), so classes are not exceptional here.

UnaryExpression:
    & UnaryExpression
    ++ UnaryExpression
    -- UnaryExpression
    * UnaryExpression
    - UnaryExpression
    + UnaryExpression
    ! UnaryExpression
    ComplementExpression
    ( Type ) . Identifier
    ( Type ) . TemplateInstance
    DeleteExpression
    CastExpression
    PowExpression
November 24, 2013
On Sunday, 24 November 2013 at 14:32:16 UTC, ilya-stromberg wrote:
> On Sunday, 24 November 2013 at 14:16:39 UTC, bearophile wrote:
>> Maxim Fomin:
>>
>>> This is neither bug not a terribale feature.
>>
>> I think the implicit question of ilya-stromberg was: how much bug-prone is this language feature?
>
> Yes, exactly. I personally was VERY surprised. My code example from real life:
>
> class Foo
> {
> }
>
> class Bar
> {
> 	Foo f;
> 	
> 	void bar()
> 	{
> 		//variable was wrongly commented here
> 		//bool f = true;
> 		
> 		if(f)
> 		{
> 			//Oops!
> 		}
> 	}
> }

This is identifiers shadowing issue. In best case you could not define boolean f, so the problem would not arise in a first place. Anyway, many artifical examples can be provided which shows that some features behave in unexpected ways which is not a reason that they are bad.
November 24, 2013
On Sunday, 24 November 2013 at 14:45:31 UTC, Maxim Fomin wrote:
> Because '!' operator provides boolean context.

Yes, but it's ambiguously. What should compiler to use:
1) pointer comparing `is null` or
2) bool comparing `cast(bool)`

What happens if `cast(bool)` operator will be added or removed?
November 24, 2013
On Sunday, 24 November 2013 at 14:50:28 UTC, Maxim Fomin wrote:
> This is identifiers shadowing issue. In best case you could not define boolean f, so the problem would not arise in a first place.

Yes, I agree that it's also can be identifiers shadowing issue. But we allow code like this:

class Foo
{
	int i;
	
	this(int i)
	{
		this.i = i;
	}
}

> Anyway, many artifical examples can be provided which shows that some features behave in unexpected ways which is not a reason that they are bad.

I repeat, this is REAL LIFE example. I just reduce it because it have unnecessary details for this case.
November 24, 2013
On Sunday, 24 November 2013 at 14:55:10 UTC, ilya-stromberg wrote:
> On Sunday, 24 November 2013 at 14:45:31 UTC, Maxim Fomin wrote:
>> Because '!' operator provides boolean context.
>
> Yes, but it's ambiguously. What should compiler to use:
> 1) pointer comparing `is null` or
> 2) bool comparing `cast(bool)`
>
> What happens if `cast(bool)` operator will be added or removed?

And if instance is null, where compiler can look for opCast? Again, why not read the spec and then ask questions?

"Notably absent from the list of overloaded unary operators is the ! logical negation operator. More obscurely absent is a unary operator to convert to a bool result. ... This only happens, however, for instances of structs. Class references are converted to bool by checking to see if the class reference is null or not. "
November 24, 2013
Maxim Fomin:

> This is identifiers shadowing issue. In best case you could not define boolean f, so the problem would not arise in a first place.

See also the discussion here:
http://d.puremagic.com/issues/show_bug.cgi?id=9521

Is it right for with to not give an error here?


struct Foo { int x; }
int x;
void main() {
    Foo f;
    with (f) {
        x++;
    }
}


Silent shadowing of global (module-level in both Python and D) names has caused me many problems along the years.

Bye,
bearophile
November 24, 2013
On Sunday, 24 November 2013 at 15:01:34 UTC, ilya-stromberg wrote:
> On Sunday, 24 November 2013 at 14:50:28 UTC, Maxim Fomin wrote:
>> This is identifiers shadowing issue. In best case you could not define boolean f, so the problem would not arise in a first place.
>
> Yes, I agree that it's also can be identifiers shadowing issue. But we allow code like this:
>
> class Foo
> {
> 	int i;
> 	
> 	this(int i)
> 	{
> 		this.i = i;
> 	}
> }
>
>> Anyway, many artifical examples can be provided which shows that some features behave in unexpected ways which is not a reason that they are bad.
>
> I repeat, this is REAL LIFE example. I just reduce it because it have unnecessary details for this case.

Many people complain about language features which are really broken, misfunctiong, or both. Sometimes they point out on cases like:

assert("Unexpected error occured");

which do not show feature failure, but language can be improved by rejecting or at least warning in such cases. However your case

class Foo
{
}

class Bar
{
	Foo f;
	
	void bar()
	{
		//variable was wrongly commented here
		//bool f = true;
		
		if(f)
		{
			//Oops!
		}
	}
}

has nothing to do with either of these two types of defficiencies. No way compiler could guess that you have bool f in mind. There is no way to improve the language because it requires blocking class to bool conversion in boolean context which is pretty nice feature and there are plenty of code which has to be broken.
November 24, 2013
On Sunday, 24 November 2013 at 15:35:40 UTC, bearophile wrote:
> Maxim Fomin:
>
>> This is identifiers shadowing issue. In best case you could not define boolean f, so the problem would not arise in a first place.
>
> See also the discussion here:
> http://d.puremagic.com/issues/show_bug.cgi?id=9521
>
> Is it right for with to not give an error here?
>
>
> struct Foo { int x; }
> int x;
> void main() {
>     Foo f;
>     with (f) {
>         x++;
>     }
> }
>
>
> Silent shadowing of global (module-level in both Python and D) names has caused me many problems along the years.
>
> Bye,
> bearophile

Yes, it is confusing. It is especially confusing in an unstable language with absent adequate spec. For example, I can learn C namespace rules, but in D case it is useless. Unfortunately what is right in cases like above depends on what Walter & Andrei think so we stuck with their opinions on the subject.

(I think emitting at least warning would be good)
November 24, 2013
On Sunday, 24 November 2013 at 15:39:20 UTC, Maxim Fomin wrote:

> No way compiler could guess that you have bool f in mind.

Sorry if I didn't explain the example properly.

The `bool f` variable was in my code and it works correctly, but compiler didn't put attention that I have identifiers shadowing issue. After big code refactoring I wrongly commented the `bool f` variable.

So, nothing happens if compiler provides identifier shadowing error - I'll just rename variable. Is it possible to implement?