Explict generic type in function by default replace this type to dynamic inside - dart

Why explict generic type in function by default replace this type to dynamic inside?
example:
class Boo {
void displayType<int>() {
print('type int to string: $int');
print('type string to string: $String');
}
}
main() {
final boo = Boo();
boo.displayType();
}
output:
type int to string: dynamic
type string to string: String
its bug?

name of generic can be existing type. So if tell any type in function, inside int can be any another type
main() {
final boo = Boo();
boo.displayType<Boo>();
}
type int to string: Boo
type string to string: String

Here <int> is not an int data type but a name of generic datatype to be passed into function.
void displayType<int>() {
print('type int to string: $int');
print('type string to string: $String');
}
Compliler builds priorities from global to local. That means - it will prioritize local variables, arguments, generic types more than global ones. For example:
int number = 2;
void someFunc(){
//local variables are in higher priorities inside their closures
int number = 3;
//will print 3
print(number);
}
You definded generic type as <int> - compiler takes it as a priority in assgning and usage operations above the actual data type named int. Knowing this - do not be confused and make generic types consisting of 1 letter as usually it is done in many documentations.
void displayType<T>() {
//now it prints int
print('type int to string: $int');
//will print dynamic
print('type generic to string: $T');
print('type string to string: $String');
}
main() {
final boo = Boo();
boo.displayType();
}

You function declaration
void displayType<int>() {
print('type int to string: $int');
print('type string to string: $String');
}
introduces a generic function with a type parameter named int.
It's exactly the same as
void displayType<T>() {
print('type int to string: $T');
print('type string to string: $String');
}
except that the type parameter is named int, which also shadows the declaration of int normally imported from dart:core.
When you then call that method without a type argument, as
boo.displayType();
the type argument T/int (name doesn't matter) is inferred by using the bound of the type parameter (because there are no method arguments to infer a type from either). It has no bound given, so it defaults to dynamic.
It's not at all clear what you are trying to do.
If you wanted a type parameter bounded by int, you can write
void displayType<T extends int>() {
print('type T to string: $T');
print('type int to string: $int');
print('type string to string: $String');
}
If you are trying to override a superclass method which is also generic, to not be generic, you can't do that. The override must have the same type parameters with the same bounds as the superclass, otherwise the override is invalid.

Related

How do I initialize non-nullable members in a constructor body?

I've created my class in Dart this way, but I'm getting the Non-nullable instance field 'text' must be initialized. Try adding an initializer expression, or add a field initializer in this constructor, or mark it 'late'. I would like to know if there's a way to do it in a 'Python' style where this kind of class creation is possible, thank you in advance.
class Lexer {
String _text;
int _pos;
String _current_char;
Lexer(String text) {
this._text = text;
this._pos = -1;
this._current_char = '';
this.advance();
}
void advance() {
this._pos++;
this._current_char = this._pos < this._text.length ? this._text[this._pos] : '';
}
}
class Lexer {
String _text;
int _pos;
String _current_char;
This declares several members with type String. Since they are declared as String and not as String?, these members are non-nullable; they are not allowed to ever be null. (This is part of the new null-safety feature from Dart 2.12.)
Dart initializes objects in two phases. When the constructor's body runs, Dart expects all member variables to already be initialized. Because your members are non-nullable and haven't been initialized to non-null values yet, this is an error. The error message explains what you can do:
Non-nullable instance field 'text' must be initialized. Try adding an initializer expression, or add a field initializer in this constructor, or mark it 'late'.
Use initializer expressions. This means using an initializer list:
Lexer(String text)
: _text = text,
_pos = -1,
_current_char = '' {
advance();
}
Note that if you're initializing members with a construction parameter of the same name, you can use shorthand:
Lexer(this._text)
: _pos = -1,
_current_char = '' {
advance();
}
Adding field initializers. This means initializing members inline in the class declaration.
class Lexer {
String _text = '';
int _pos = -1,
String _current_char = '';
Marking your members as late. This means that you promise that the variables will be initialized before anything attempts to use them.
class Lexer {
late String _text;
late int _pos,
late String _current_char;
Making your members nullable, which allows them to be implicitly null by default:
class Lexer {
String? _text;
int? _pos,
String? _current_char;
However, that will require that all accesses explicitly check that the members aren't null before using them.
You also might want to read: Dart assigning to variable right away or in constructor?

How to specify the type of a function parameter with combined type CustomStringConvertible and RawRepresentable?

I want a generic function that can instantiate object of a few different enum types I have by supplying the enum type and the Int raw-value. These enums are also CustomStringConvertible.
I tried this:
func myFunc(type: CustomStringConvertible.Type & RawRepresentable.Type, rawValue: Int)
which results in 3 errors:
Non-protocol, non-class type 'CustomStringConvertible.Type' cannot be used within a protocol-constrained type
Non-protocol, non-class type 'RawRepresentable.Type' cannot be used within a protocol-constrained type
Protocol 'RawRepresentable' can only be used as a generic constraint because it has Self or associated type requirements
Forgetting about 'CustomStringConvertible` for now, I also tried:
private func myFunc<T: RawRepresentable>(rawValue: Int, skipList: [T]) {
let thing = T.init(rawValue: rawValue)
}
But, although code completion suggests it, leads to an error about the T.init(rawValue:):
Cannot invoke 'init' with an argument list of type '(rawValue: Int)'
How can I form a working generic function like this?
The issue is that T.RawValue can be something else than Int with your current type constraints. You need to specify that T.RawValue == Int in order to pass your rawValue: Int input parameter to init(rawValue:).
func myFunc<T: RawRepresentable & CustomStringConvertible>(rawValue: Int, skipList: [T]) where T.RawValue == Int {
let thing = T.init(rawValue: rawValue)
}

'init' is unavailable: use 'withMemoryRebound(to:capacity:_)' to temporarily view memory as another layout-compatible type [duplicate]

I have a c api that returns a null terminated string that is an array of type unsigned char* (which would correspond to UnsafePointer<UInt8>).
Swift has the initializer String(validatingUTF8:), but the argument has to be UnsafePointer<CChar> (a.k.a. UnsafePointer<Int8>), and there is no trivial way to convert between the two.
How do I convert from this null-terminated c-string to a Swift string?
In Swift 3, String has two initializers
public init(cString: UnsafePointer<CChar>)
public init(cString: UnsafePointer<UInt8>)
therefore it can be created from (null-terminated) sequences of both signed and unsigned characters. So
let s = String(cString: yourCharPointer)
should just work.
String has another initializer
public init?(validatingUTF8 cString: UnsafePointer<CChar>)
which fails on ill-formed UTF-8 sequences instead of replacing them
by the replacement characters. This init method has no counterpart
taking unsigned characters.
Taking the existing implementations in CString.swift as examples, it is not too difficult to add this as an extension:
extension String {
public init?(validatingUTF8 cString: UnsafePointer<UInt8>) {
guard let (s, _) = String.decodeCString(cString, as: UTF8.self,
repairingInvalidCodeUnits: false) else {
return nil
}
self = s
}
}
and then
if let s = String(validatingUTF8: yourCharPointer) {
print(s)
} else {
print("invalid UTF-8")
}
also works with (null-terminated) sequences of both signed and unsigned characters.

Why CustomStringConvertible protocol not working for Int?

public func +<T: CustomStringConvertible>(lhs: T, rhs: T)->String{
return lhs.description+rhs.description
}
let a:String = "A"
let i:Int = 0
print(a+i)
I am overloading '+' operator for CustomStringConvertible types. String and Int both confirms CustomStringConvertible protocol but it gives an error: "binary operator '+' cannot be applied to operands of type 'String' and 'Int' print(a+i)". It working fine when I apply it to 'String'+'NSNumber'.
don't know what is going behind the scene. why it is not working?
The problem is firstly (believe it or not) String doesn't conform to CustomStringConvertible. You'll therefore want to conform it yourself in order for it to return self for description (probably easier than writing another overload to deal with strings independently).
extension String:CustomStringConvertible {
public var description: String {
return self
}
}
Secondly, you need two generic parameters for your + overload, in order to allow it to accept different types for both parameters, while ensuring that both parameters conform to CustomStringConvertible:
public func +<T: CustomStringConvertible, U:CustomStringConvertible>(lhs: T, rhs: U)->String{
return lhs.description+rhs.description
}

How to adhere to protocol method with a Raw type in method argument?

protocol Measurement {
mutating func convert(#toUnit: String)
}
enum MassUnit : String {
case Milligram = "mg"
}
enum VolumeUnit : String {
case Milliliter = "ml"
}
struct Mass : Measurement {
mutating func convert(#toUnit: MassUnit)
// Build error: Does not adhere to 'Measurement'
}
struct Volume : Measurement {
mutating func convert(#toUnit: VolumeUnit)
// Build error: Does not adhere to 'Measurement'
}
func +<T: Measurement> (left:T, right:T) -> Measurement {
let newRightValue = right.convert(toUnit: left.unit)
return T(quantity: left.quantity + newRightValue.quantity , unit: left.unit)
}
How can I make Mass adhere correctly to Measurement? What change in the Measurement protocol is needed to get it to work with enum of type String?
Question updated with more information about why the convert method signature should say something about the argument given. The code is part of an open source Unit framework i'm building called Indus Valley
You probably confuse enum MassUnit : String with inheritance.
Contrary to class ChildClass : ParentClass which denotes that ChildClass inherits from ParentClass, enum MassUnit : String has a slightly different meaning, telling that the rawType of the enum is String, not that the enum inherits the String type.
So MassUnit is not of type String. You MassUnit's rawValues are of type String, but to access that you need to call the rawValue property of the enum to get that String equivalent.
Therefore, mutating func convert(#toUnit: String) and mutating func convert(#toUnit: MassType) are not compatible, as MassType is not a String itself. Only its rawValue is.
When dealing with your unit conversions, I advise not trying to use Strings to represent the units when converting the way you've got setup above. That's going to make your code complicated with checking the String can be converted to its respective enum every time you want to make a conversion. Also, what if you want to use the a MassUnit/VolumeUnit instead of a String?
I would recommend using the a setup similar to what I've outlined below. It references my previous answer - How to represent magnitude for mass in Swift?
(Note - I've excluded anything to do with the volume because it's basically the same as the implementation for the mass)
I'd make the units like so:
protocol UnitProtocol {
var magnitude: Int { get }
init?(rawValue: String)
}
// Taken from my previous answer.
enum MassUnit: String, UnitProtocol, Printable {
case Milligram = "mg"
case Gram = "g"
var magnitude: Int {
let mag: Int
switch self {
case .Milligram: mag = -3
case .Gram : mag = 0
}
return mag
}
var description: String {
return rawValue
}
}
// Not making this a method requirement of `UnitProtocol` means you've only got to
// write the code once, here, instead of in every enum that conforms to `UnitProtocol`.
func ordersOfMagnitudeFrom<T: UnitProtocol>(unit1: T, to unit2: T) -> Int {
return unit1.magnitude - unit2.magnitude
}
Then I'd make the masses/volumes like so:
protocol UnitConstruct {
typealias UnitType: UnitProtocol
var amount: Double { get }
var unit : UnitType { get }
init(amount: Double, unit: UnitType)
}
struct Mass : UnitConstruct {
let amount: Double
let unit : MassUnit
}
Now for the converting function! Using a global function means you don't need to rewrite the code for every type than conforms to UnitConstruct.
func convert<T: UnitConstruct>(lhs: T, toUnits unit: T.UnitType) -> T {
let x = Double(ordersOfMagnitudeFrom(lhs.unit, to: unit))
return T(amount: lhs.amount * pow(10, x), unit: unit)
}
// This function is for converting to different units using a `String`,
// as asked in the OP.
func convert<T: UnitConstruct>(lhs: T, toUnits unit: String) -> T? {
if let unit = T.UnitType(rawValue: unit) {
return convert(lhs, toUnits: unit)
}
return nil
}
You can then use the previous code like so:
let mass1 = Mass(amount: 1.0, unit: .Gram)
let mass2 = convert(mass1, toUnits: .Milligram) // 1000.0 mg
// Or, converting using Strings:
let right = convert(mass1, toUnits: "mg") // Optional(1000.0 mg)
let wrong = convert(mass1, toUnits: "NotAUnit") // nil

Resources