Deduced conflicting types without template - operator-overloading

I'm trying to create a type that can store either an int, a double, or an uint, like so:
struct Value
{
/*...*/
Value& operator=(const int value) { /*...*/ }
Value& operator=(const double value) { /*...*/ }
Value& operator=(const uint value) { /*...*/ }
operator int() const { /*...*/ }
operator double() const { /*...*/ }
operator uint() const { /*...*/ }
}
I got errors about "deduced conflicting types" when I'm trying to use it. I read somewhere that "deduction guide" can help but it seems to require template. My type doesn't need template.
Is there a solution to use this Value type without the need to cast it in int,double or uint everytime?
Value v;
v=123;
// I would like to type:
std::clamp(v,0,1234); // error
// But I need to type:
std::clamp(int(v),0,1234); // ok
I also have the same kind of problem with operator (with different error messages)
int x=v+12;
I think I should add more operator overloading, but I don't found which one.

// I would like to type:
std::clamp(v,0,1234); // error
Try with
// .......VVVVV
std::clamp<int>(v, 0, 1234);
The problem is the signature of std::clamp() is
template<class T>
constexpr const T& clamp( const T& v, const T& lo, const T& hi );
so if you call it without explicating T,
std::clamp(v, 0, 1234);
the template type T is deduced Value, from v, and int, from 0 and from 1234.
Given the conflicting types, you get an error.
If you explicit the template type
// .......VVVVV
std::clamp<int>(v, 0, 1234);
there is no more deduction, the compiler expect an int in first position so the operator int () is called over v.

Related

Why enums can't be used in const constructors in Flutter?

can someone tell me if there's a way to use enhanced enums in const constructors? I tried both named constructors and factory constructors, with no luck:
enum MyEnum {
first('first-string'),
second('second-string');
final String string;
const MyEnum(this.string);
}
class MyClass {
final String input;
const MyClass({required this.input});
const MyClass.first({
this.input = MyEnum.first.string, //error
});
factory MyClass.second() {
return const MyClass(input: MyEnum.second.string); //error
}
}
Named constructor gives error: The default value of an optional parameter must be constant
Factory constructor gives error: A value of type 'Null' can't be assigned to a parameter of type 'String' in a const constructor. Try using a subtype, or removing the keyword 'const'
Right now the only solution I found was to replace enum with a class containing static const params, like this:
class MyEnumClass {
static const String first = 'first-string';
static const String second = 'second-string';
}
You can use enums if you use the enum type itself for the member.
enum MyEnum {
first('first-string'),
second('second-string');
final String string;
const MyEnum(this.string);
}
class MyClass {
final MyEnum _input;
String get input => _input.string;
const MyClass({required MyEnum input}) : _input = input;
const MyClass.first({
MyEnum input = MyEnum.first,
}) : _input = input;
factory MyClass.second() {
return const MyClass(input: MyEnum.second);
}
}
In general, getters are equivalent to function calls and aren't constant expressions. (There are a some exceptions, and maybe enum members should be too.)

Is it possible to declare a Map type that requires all enum values to be present as keys?

How can I require the Dart compiler to warn me when I forget to include all members of an enum in a map? For example, in the following:
enum Size {
small,
medium,
large,
}
// This is a valid Dart code. Dart compiler doesn't require `Size.large` to be present.
final Map<Size, ButtonSize> sizeMap = {
Size.small: const MyClass(),
Size.medium: const MyClass(),
};
The Dart compiler isn't that restrictive. It doesn't require all enum values to be present in the Map, so I can't be sure that the following code will return an instance of MyClass. It might resolve to null:
final MyClass instance = sizeMap[Size.small]; // unsafe
I have to either do this:
final MyClass? instance = sizeMap[Size.small]; // `instance` might be `null`
or this:
final MyClass instance = sizeMap[Size.small] as MyClass; // `instance` might still be `null`, but we're pretending it's not.
Both solutions are far from perfect. The first one implies further null checks in the code, the second one smells because of typecasting.
Is there any way to declare the type of sizeMap so that all enum values must be present?
Instead of using a Map, you'd be better off with a function and a switch statement:
enum Size {
small,
medium,
large,
}
class MyClass {
const MyClass();
}
MyClass mapSize(Size size) {
switch (size) {
case Size.small:
return const MyClass();
case Size.medium:
return const MyClass();
}
}
the above code generates a compile-time error from not handling all enum values:
Error: A non-null value must be returned since the return type 'MyClass' doesn't allow null.
With null-safety, the above code cannot be executed until the above problem is fixed.
Additionally, dart analyze will produce a more descriptive warning:
Missing case clause for 'large'. Try adding a case clause for the missing constant, or adding a default clause. • missing_enum_constant_in_switch
If you want to use a Map because you want to allow it to be mutated, you could provide separate functions to set and get values:
var _smallValue = const MyClass();
var _mediumValue = const MyClass();
var _largeValue = const MyClass();
MyClass mapSize(Size size) {
switch (size) {
case Size.small:
return _smallValue;
case Size.medium:
return _mediumValue;
case Size.large:
return _largeValue;
}
}
void setMappedSize(Size size, MyClass value) {
switch (size) {
case Size.small:
_smallValue = value;
break;
case Size.medium:
_mediumValue = value;
break;
case Size.large:
_largeValue = value;
break;
}
}
If you find that to be too verbose, and you just want callers to avoid returning null, you could wrap a Map internally:
const _defaultValue = const MyClass();
final _sizeMap = <Size, MyClass>{};
MyClass mapSize(Size size) => _sizeMap[size] ?? _defaultValue;
void setMappedSize(Size size, MyClass value) => _sizeMap[size] = value;

Avoid duplication of null type checking in Dart

My current goal is to remove this code duplication:
final int? myNullableInt = 10;
/// Everywhere I need to do this null verification:
if (myNullableInt == null) return null;
return someOtherMethodThatReceivesANonNullableInt(myNullableInt);
I want to convert to something like we have in Kotlin:
final int? myNullableInt = 10;
return myNullableInt?.apply((myInt) => someOtherMethodThatReceivesANonNullableInt(myInt));
I did it:
extension ApplyIfNotNull on Object? {
T? apply<T extends Object?>(Object? obj, T? Function(Object) fn) {
if (obj == null) return null;
return fn(obj);
}
}
But this gives me a static error:
The argument type 'Object' can't be assigned to the parameter type 'int'.
Note: this should work with all types, e.g ints, Strings, double and MyOwnClassTypes.
Is there something I can do? or am I missing something?
extension ApplyIfNotNull on Object? {
T? apply<T extends Object?>(Object? obj, T? Function(Object) fn) {
if (obj == null) return null;
return fn(obj);
}
}
That doesn't work because it declares that the callback be capable of accepting any Object argument, but you're presumably trying to use it with a function that accepts only an int argument. It's also unclear why you've made an extension method since it doesn't involve the receiver (this) at all.
You need to make your function generic on the callback's argument type as well:
R? applyIfNotNull<R, T>(T? obj, R Function(T) f) =>
(obj == null) ? null : f(obj);
(That's the same as what I suggested in https://github.com/dart-lang/language/issues/360#issuecomment-502423488 but with the arguments reversed.)
Or, as an extension method, so that it can work on this instead of having the extra obj argument:
extension ApplyIfNotNull<T> on T? {
R? apply<R>(R Function(T) f) {
// Local variable to allow automatic type promotion. Also see:
// <https://github.com/dart-lang/language/issues/1397>
var self = this;
return (self == null) ? null : f(self);
}
}
Also see https://github.com/dart-lang/language/issues/360 for the existing language feature request and for some other suggested workarounds in the meantime.

Passing the correct type to addch() [ncurses, Linux]

In following a tutorial on how to use ncurses with swift I have been facing the error:
main.swift:31:15: error: cannot convert value of type 'UInt?' to expected argument type 'chtype' (aka 'UInt32')
addch(UInt("*"))
^~~~~~~~~
It complains about the type, but when I change it to UInt32 the error changes to error: ambiguous use of 'init' addch(UInt32("*"))
Question
How to pass the correct value type to addch?
The entire code for reference:
import Foundation
import CNCURSES
import Glibc
enum Signal:Int32 {
case INT = 2
case WINCH = 28
}
typealias SignalHandler = __sighandler_t
func trap(signum:Signal, action:#escaping SignalHandler) {
signal(signum.rawValue, action)
}
func getmaxyx(window:UnsafeMutablePointer<WINDOW>, y:inout Int32, x:inout Int32) {
x = getmaxx(window)
y = getmaxy(window)
}
func getcuryx(window:UnsafeMutablePointer<WINDOW>, y:inout Int32, x:inout Int32) {
x = getcurx(window)
y = getcury(window)
}
func drawbox(numlines:Int32, numcols:Int32) {
for y in 0...numlines-1 {
for x in 0...numcols {
move(y, x)
if y == 0 || y == numlines-1 {
addch(UInt("*"))
} else {
if x == 0 || x == numcols {
addch(UInt("*"))
}
}
}
}
refresh()
}
[...]
initscr()
noecho()
curs_set(0)
getmaxyx(window:stdscr, y:&maxy, x:&maxx)
drawbox(numlines:maxy, numcols:maxx)
center(text:"Hello world!", numlines:maxy, numcols:maxx)
while true {
select(0, nil, nil, nil, nil)
}
Seeing the error message, you need to pass a UInt32 value to addch(_:).
The return type of UInt("*") is UInt?, and its actual value is always nil. (Simple String to UInt conversion tries to interpret the String as decimal integer.)
When you want a character code as UInt32, you may need to write something like this:
addch(("*" as UnicodeScalar).value)
If your code would have many more addch(_:) calls, you can define a simple wrapper for it.
For example:
func addCh(_ us: UnicodeScalar) {
addch(us.value)
}
addCh("*")
With explicitly annotating as UnicodeScalar, String Literals are interpreted as UnicodeScalar and its value property is of type UInt32.
The correct (and documented type) is chtype:
int addch(const chtype ch);
int waddch(WINDOW *win, const chtype ch);
int mvaddch(int y, int x, const chtype ch);
int mvwaddch(WINDOW *win, int y, int x, const chtype ch);
int echochar(const chtype ch);
int wechochar(WINDOW *win, const chtype ch);
The number of bits in chtype depends upon the system. In ncurses' header files, it is by default declared as unsigned, but that can be overridden when configuring/building ncurses.
X/Open (see addch and <curses.h>) says nothing more explicit than that.
Of course, whatever it happens to be in swift is an implementation detail of the binding, and unless documented, is subject to change.

What is analogue of Objective C static variable in Swift?

It was very convenient to have static variables in Objective C (static variable's value is maintained throughout all function/method calls), however I couldn't find anything like this in Swift.
Is there anything like this?
This is an example of static variable in C:
void func() {
static int x = 0;
/* x is initialized only once across four calls of func() and
the variable will get incremented four
times after these calls. The final value of x will be 4. */
x++;
printf("%d\n", x); // outputs the value of x
}
int main() { //int argc, char *argv[] inside the main is optional in the particular program
func(); // prints 1
func(); // prints 2
func(); // prints 3
func(); // prints 4
return 0;
}
After seeing your updated answer, here is the modification for your Objective-C code:
func staticFunc() {
struct myStruct {
static var x = 0
}
myStruct.x++
println("Static Value of x: \(myStruct.x)");
}
Call is anywhere in your class
staticFunc() //Static Value of x: 1
staticFunc() //Static Value of x: 2
staticFunc() //Static Value of x: 3
Declare the variable at the top level of a file (outside any classes) which is called global variable.
variables at the top level of a file are initialised lazily! So you
can set the default value for your variable to be the result of
reading the file, and the file won't actually be read until your code
first asks for the variable's value.
Reference from HERE.
UPDATE:
From your C example you can achieve same thing in swift this way:
var x = 0 //this is global variable
func staticVar() {
x++
println(x)
}
staticVar()
x //1
staticVar()
x //2
staticVar()
x //3
Tested with playground.
From Apple Document:
In C and Objective-C, you define static constants and variables
associated with a type as global static variables. In Swift, however,
type properties are written as part of the type’s definition, within
the type’s outer curly braces, and each type property is explicitly
scoped to the type it supports.
You define type properties with the static keyword. For computed type
properties for class types, you can use the class keyword instead to
allow subclasses to override the superclass’s implementation. The
example below shows the syntax for stored and computed type
properties:
struct SomeStructure {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
// return an Int value here
}
}
enum SomeEnumeration {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
// return an Int value here
}
}
class SomeClass {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
// return an Int value here
}
class var overrideableComputedTypeProperty: Int {
// return an Int value here
}
}
NOTE
The computed type property examples above are for read-only computed type >properties, but you can also define read-write computed
type properties with the same syntax as for computed instance
properties.