Unary negation operator overloading in D - operator-overloading

Code
struct test
{
private real value;
this(real value)
{
this.value = value;
}
bool opUnary(string op)() if (op == "!")
{
return !value;
}
}
void main()
{
test a = 123.12345;
bool b = !a;
}
Compilation error
prog.d(19): Error: expression a of type test does not have a boolean value
http://ideone.com/Kec81
Also tested on dmd 2.053, 2.054
What's wrong with my code?

You cannot overload the ! operator in D - see http://www.d-programming-language.org/operatoroverloading.html#Unary for a list of overloadable unary operators. Without knowing what you're doing, it's hard to suggest a work around, it might be worth looking at alias this though - http://www.d-programming-language.org/class.html#AliasThis.

Related

How come Flutter doesn't accept null checking within an 'if' statement [duplicate]

I'm upgrading a personal package that is based on the Flutter framework. I noticed here in the Flutter Text widget source code that there is a null check:
if (textSpan != null) {
properties.add(textSpan!.toDiagnosticsNode(name: 'textSpan', style: DiagnosticsTreeStyle.transition));
}
However, textSpan! is still using the ! operator. Shouldn't textSpan be promoted to a non-nullable type without having to use the ! operator? However, trying to remove the operator gives the following error:
An expression whose value can be 'null' must be null-checked before it can be dereferenced.
Try checking that the value isn't 'null' before dereferencing it.
Here is a self-contained example:
class MyClass {
String? _myString;
String get myString {
if (_myString == null) {
return '';
}
return _myString; // <-- error here
}
}
I get a compile-time error:
Error: A value of type 'String?' can't be returned from function 'myString' because it has a return type of 'String'.
Or if I try to get _mySting.length I get the following error:
The property 'length' can't be unconditionally accessed because the receiver can be 'null'.
I thought doing the null check would promote _myString to a non-nullable type. Why doesn't it?
My question was solved on GitHub so I'm posting an answer below.
Dart engineer Erik Ernst says on GitHub:
Type promotion is only applicable to local variables. ... Promotion of an instance variable is not sound, because it could be overridden by a getter that runs a computation and returns a different object each time it is invoked. Cf. dart-lang/language#1188 for discussions about a mechanism which is similar to type promotion but based on dynamic checks, with some links to related discussions.
So local type promotion works:
String myMethod(String? myString) {
if (myString == null) {
return '';
}
return myString;
}
But instance variables don't promote. For that you need to manually tell Dart that you are sure that the instance variable isn't null in this case by using the ! operator:
class MyClass {
String? _myString;
String myMethod() {
if (_myString == null) {
return '';
}
return _myString!;
}
}
The Error:
Let's say, this is your code and you're doing a null check on the instance variable and still seeing an error:
class Foo {
int? x;
double toDouble() {
if (x != null) return x.toDouble(); // <-- Error
return -1;
}
}
The method 'toDouble' can't be unconditionally invoked because the receiver can be 'null'.
The error you see in code like this is because Getters are not promoted to their non-nullable counterparts. Let's talk about the reason why.
Reason of the Error:
Let's say, there's a class Bar which extends Foo and overrides x field and implemented like this:
class Bar extends Foo {
#override
int? get x => (++_count).isOdd ? 1 : null;
int _count = 0;
}
Now, if you do
Bar().toDouble();
You would have run into a runtime null error, which is why getters type promotion is prohibited.
Solutions:
We need to cast away nullability from int?. There are generally 3 ways to do this.
Use local variable (Recommended)
double toDouble() {
final x = this.x; // <-- Use a local variable
if (x != null) return x.toDouble();
return -1;
}
Use ?. with ??
double toDouble() {
return x?.toDouble() ?? -1; // Provide a default value
}
Use null-assertion operator (!)
You should only use this solution when you're 100% sure that the variable (x) will never be null.
double toDouble() {
return x!.toDouble(); // Null assertion operator
}
style: Theme.of(context).textTheme.headline5!.copyWith(
style: Theme.of(context).textTheme.headline5!.copyWith(
color: Colors.white
Try making the call conditional using ? or a null safety checker - !

How to declare a variable depending on if statement in Dart like in Kotlin?

How to declare a variable depending on if statement in Dart? In Kotlin it would look like this:
val max = if (a > b) {
a
} else {
b
}
Is it even possible in Dart?
#pskink's answer in the comment is correct but it didn't show how you would be able to do it in this scenario. Here is how you can do it in your scenario:
final max= a > b ? a : b;
The final keyword in Dart is the same as the val keyword in Kotlin. You will not be able to change the value of the variable. You could also use the var keyword in Dart which is the same as Kotlin's var keyword. You will be able to change the value of the variable after declaring it. You might be confused with the one-liner code since there isn't any if or else statements inside it. The code above is called a ternary operator.
Here is an explanation for it:
(condition/expresssion) ? val1(if true execute this) : val2(if false execute this)
For more than one statement, we can use a method by declaring its type as int.
void main() {
print(declareVariable());
}
int a = 10;
int b = 30;
int declareVariable() {
if(b < a){
return 1;
}
else if(b > a) {
return 2;
}
else {
return 0;
}
}
Edited :
We can declare more then one condition in single line in the same way.
var singleLine = b < a ? 1 : b > a ? 2 : 0;
This will print out the same answer as method.

In Swift, why is this equals operator in this conditional even necessary? [duplicate]

Not sure what I'm doing wrong here, but here's the trivial code that's breaking:
if 10 & (1<<18) {
return
}
This gives me:
'Int' is not convertible to 'Bool'
What is wrong?
Unlike in C where you can write...
if (x) { }
... which is really a non-zero check:
if (x != 0) { }
You must test for a boolean condition in Swift. Add != 0 to your statement:
if 10 & (1<<18) != 0 {
return
}
Swift 4 : Check that
Your method has a correct return type which the caller is expecting
eg: func yourMethod() -> Bool
The caller method has parentheses () at the end yourMethod()

Swift 3: Int is not convertible to Bool in bitwise operation

Not sure what I'm doing wrong here, but here's the trivial code that's breaking:
if 10 & (1<<18) {
return
}
This gives me:
'Int' is not convertible to 'Bool'
What is wrong?
Unlike in C where you can write...
if (x) { }
... which is really a non-zero check:
if (x != 0) { }
You must test for a boolean condition in Swift. Add != 0 to your statement:
if 10 & (1<<18) != 0 {
return
}
Swift 4 : Check that
Your method has a correct return type which the caller is expecting
eg: func yourMethod() -> Bool
The caller method has parentheses () at the end yourMethod()

Swift Boolean checking

So in Objective-C when using Booleans it's possible, and encouraged, to write code using a variable's non-zero value as it's boolean value, which means you can write code like this:
if (someBool) {
// Stuff
}
Also, there are reasons why code like the following is discouraged:
if (someBool == YES) {
// Might run into problems here
}
The reasons why checking a boolean against another boolean are better explained here, but briefly the issue is just that when you're comparing equality to YES or NO directly, you're actually comparing against 1 and 0, respectively. Since Objective-C allows for using non-zero values as a truth value, you could end up comparing something that should be considered true against YES and have the expression resolve to NO, e.g.
int trueNumber = 2;
if (trueNumber == YES) {
// Doesn't run because trueNumber != 1
}
Is this still an issue in Swift? Code style issues aside, if I see something like the following
var someBool = true
if someBool == true {
// stuff
}
is that going to be an issue, or does it not really matter? Are these C-style comparisons still happening under the hood, or is there something built into the Swift BooleanType that prevents these issues?
The if <something> {} structure in Swift requires the <something> to conform to the BooleanType protocol which is defined like this:
public protocol BooleanType {
/// The value of `self`, expressed as a `Bool`.
public var boolValue: Bool { get }
}
If the type doesn't conform to this protocol, a compile-time error is thrown. If you search for this protocol in the standard library you find that the only type that conforms to this protocol is Bool itself. Bool is a type that can either be true or false. Don't think of it as the number 1 or 0, but rather as On/Off Right/Wrong.
Now this protocol can be conformed to by any nominal type you want, e.g.:
extension Int : BooleanType {
public var boolValue : Bool {
return self > 0
}
}
Now if you do this (you shouldn't honestly), you're defining it by yourself what "True" and "False" means. Now you'd be able to use it like this (again, don't do this):
if 0 {
...
}
Swift has Bool type. This is different from objective-c's BOOL which is not actual type. It is actually typedef unsigned char. When swift expects Bool you have to give it Bool otherwise it is compile error. The following code will not compile because check is not Bool
let check = 2
if check {
}
But this will work because == returns Bool
let check = 2
if check == 2 {
}
To understand the ObjC style, you need to go back to C. In C, this statement:
if (something) {
// Do something
}
will evaluate to false if something is null or 0. Everything else evaluate to true. The problem is C doesn't have a boolean type. Objective-C added YES and NO which is basically 1 and 0. So:
if (aBoolValue == YES) { } // Work as expected
if (anIntValue == YES) { } // False unless anIntValue == 1
The "discouraged" recommendation was to align with the behaviour in C. Swift has no such backward compatibility requirements. You can't write these:
if anIntValue { } // Syntax error
if anObject { } // Syntax error
Instead, the expression must evaluate to a boolean value:
if anIntValue != 0 { } // Ok
if anObject != nil { } // Ok