Why are Bitwise Enum index values not allowed to be used as constants in Dart?
ie:
enum Foo {
item1,
item2,
}
enum Bar {
item1,
item2,
}
const fooBar = Foo.item1.index | Bar.item2.index;
Thank you,
Jon
If you take a look into the Enum class from dart:core you will find that the index is a getter, which is not compile time constant; Thus, you cannot assign it to a const variable.
https://api.dart.dev/stable/2.17.1/dart-core/Enum/index.html
Apparently there were opened issue to support bitwise Enums in Dart. See #33698 (There is a workaround class provided in one of the replies) and #158.
Related
Consider that I have a two class and a enum.
one of its class have a parameter as Enum type
enum A { B, C }
class Q {
Q(A a);
}
and Another class is of generic type T which take a one parameter as T type in constructor. Question is how do you convert this class's parameter type T into A inside of its own class ?
class C<T> {
T a;
C(this.a);
void getType(){
if(T == A) Q(a); /* The arugument type 'T' can't be assigned to Parameter type 'A'
cause Class Type is still 'T' */
}
}
This code contain more than 4 enum and each class for its Type. For reproducible purpose, I reduced to one.
Do an explicit cast to A. Doing a comparison of types like this likely doesn't do implicit type conversion like it would when checking for null in null-safe Dart. Dart isn't able to see that a is actually of type A even with your if statement.
So just do a as A.
class C<T> {
T a;
C(this.a);
void getType(){
if(T == A) Q(a as A);
}
}
I have noticed that generic methods can have type arguments which are enums which does not make sense to me a type arguments indicate the type of object. So why can enums be used a type?
enum specifies a type just like any other type declaration, and you specify types to make use of static-type-checking.
enum Direction { north, east, south, west }
void main() {
Direction d = Direction.north;
d = 42; // Error. Cannot assign an `int` to a `Direction`.
int i = Direction.west; // Error. Cannot assign a `Direction` to an `int`.
}
Since enum declares a type, there's no reason why enum types shouldn't be allowed as type arguments for generics, just like for any other type.
I have an enum of type String which needs to have multiple variables that have the same value. My enum looks something like this:
class MyClass {
enum MyEnum: String {
case blahA = "blaha"
case blahB = "blahb"
...
static var blahD = "blah"
static var blahE = "blah"
}
}
The reason why I'm using static var's in the above construction is because both "blahD" and "blahE" need to reference the same String value, used in different places (don't ask me why, it just has to be this way). However, I have a method where I need to pass in the value of the enum as follows:
if let testString = myString(foo: MyEnum.blahD) {...}
I unfortunately am getting the following compilation error:
Cannot convert value of type "String" to expected argument type "MyClass.MyEnum".
How do I get around passing the above variable which has duplicate values in my enum in the method, but cast it to the type of "MyClass.MyEnum"?
You can do this if you make the extra case reference the other enum case directly instead of just assigning them the same string value:
class MyClass {
enum MyEnum: String {
case blahA = "blaha"
case blahB = "blahb"
...
case blahD = "blah"
static var blahE = MyEnum.blahD
}
}
Then you can pass MyEnum.blahE the same way you would pass MyEnum.blahD
If the function takes a value of type MyEnum, you cannot do this. The type properties blahD and blahE are simply not of that type. Only the cases of the enum are of type MyEnum.
The function parameter's type must be changed to String.
The only other way around it would be to add a case to the enum that has a raw value matching the value of those two properties: case blahDOrE = "blah". Then you could construct that case: MyEnum(rawValue: MyEnum.blahD), but I can't see that being very useful.
I'm using an enum variable called BuildingType in a class initializer (of a class called Building).
This enum is defined outside the class because I want to use it also in other places.
The autocomplete for this enum is not working properly when initializing the variable typeOfBuilding.
Example code:
enum BuildingType {
case Flat, House, Villa
}
class Building {
var type : BuildingType = BuildingType.House
var floors : Int = 1
init(typeOfBuilding : BuildingType, numFloors : Int) {
self.type = typeOfBuilding
self.floors = numFloors
}
}
var myBuilding : Building = Building(typeOfBuilding: BuildingType.Flat , numFloors: 3)
So if I type "... typeOfBuilding: BuildingType." (when initializing myBuilding) 'floors' and 'type' are shown, and not the enum values.
I must be doing something wrong here but what?
This is a pretty weird bug
It occurs when you attempt to pass an enum into an argument of an initialiser, autocomplete will fail and instead of suggesting the enum cases after typing Enum., it will list the instance members of the class you’re calling the initialiser on. If you try and use the single dot syntax (.Case), autocomplete will also fail, but instead of displaying the list of instance members, it simply won't display anything.
I initially thought it may have had something to do with the naming of your enum and class (BuildingType & Building), but this is not the case.
This bug only appears to be present in initialisers with multiple arguments (one of which being an enum). I couldn’t reproduce this issue with single argument initialisers.
The reproducibility appears to depend on whether the initialiser is 'complete'. I'm considering an initialiser to be 'complete' if it has all argument names and values (except the enum) defined. For example:
// Incomplete (foo is one argument of many)
let baz = Baz(foo: Foo.
// Semi-Complete (before you assign the second parameter a value)
let baz = Baz(foo: Foo., string: <String Placeholder>)
// Complete
let baz = Baz(foo: Foo., string: "")
// Complete (note the lack of the last bracket)
let baz = Baz(param: 0, foo: Foo.
Here is my test setup (Xcode 7.3, Swift 2.2):
enum Foo {
case Bar
}
class Baz {
var iReallyShouldntBeDisplayedHere = 0
init(foo:Foo, string:String) {}
init(foo: Foo) {}
}
And here is a list of cases where I've found the bug does & doesn't occur:
// Enum is the only argument
// CORRECT: accepting the initialiser's autocomplete (so it's 'complete'), then typing "Foo." brings up autocomplete options for enum cases
let baz = Baz(foo: Foo.)
// CORRECT: typing the initialiser yourself (so it's 'incomplete'), then typing "Foo." in the first parameter brings up autocomplete options for enum cases
let baz2 = Baz(foo: Foo.
// Enum is one argument of many
// INCORRECT: accepting the initialiser's autocomplete (so it's 'semi-complete'), then typing "Foo." in the first parameter brings up Baz's instance members ("iReallyShouldntBeDisplayedHere")
let baz3 = Baz(foo: Foo., string: <String Placeholder>)
// CORRECT: typing the initialiser yourself (so it's 'incomplete'), and typing "Foo." in the first parameter brings up enum cases
let baz4 = Baz(foo: Foo.
// Single dot syntax (where enum is one argument of many)
// CORRECT: typing the initialiser yourself (so it's 'incomplete'), and typing "." in the first parameter brings up enum cases
let baz5 = Baz(foo:.
// CORRECT: accepting the initialiser's autocomplete (so it's 'semi-complete'), then typing "." in the first parameter brings up enum cases
let baz6 = Baz(foo:., string: <String Placeholder>)
// INCORRECT: modifying the foo: argument once the initialiser is 'complete' by typing "." in the first parameter doesn't generate the autocomplete list
let baz7 = Baz(foo:., string: "")
I also tried this where foo: is the last argument, but the initialiser always has to be complete in that case, so it always fails. I did try with initialisers that take 3 arguments, but it appears to have the same behaviour as an initialiser with 2 arguments.
If anyone knows of any more cases where this bug can be reproduced, I'd love to know!
In Unity3D we are able to make a field accessible inside the editor by marking it as public. This then allows assigning the field's variable in the GUI instead of hard-coding it. This C# code for example will show a "speed" field that can be manually edited during development. It will default to 10 if left unmodified:
public class Example : MonoBehaviour {
public float speed = 10.0F;
}
I tried doing this in F# with automatic properties:
type Example() =
inherit MonoBehaviour()
member val speed = 10.f with get,set
but this doesn't work. It does, however, work if I use explicit properties
[<DefaultValue>] val mutable speed : float32
but this has the drawback of not being able to specify a default value in the same expression.
Aren't explicit and automatic properties compiling down to the same thing, with the only difference being that explicit properties are always initialized to zero? And how can I declare the equivalent of the C# code in F#?
I think you are playing a little loosely with the terms "field" and "property".
The Unity editor doesn't bind properties automatically, and the first example you've provided is F#'s auto-properties. For the record, you couldn't bind the following C# in Unity editor pane either:
// does not bind in editor either
class Example : MonoBehavior {
public float speed { get; set; }
}
You have to use the code with [DefaultValue] and just initalize it in the constructor or alternatively have a let-bound private field that is tagged [SerializeField] and write your own property wrapper:
type Example () =
[<SerializeField>]
let mutable _speed = 10f
member this.speed
with get () = _speed
and set val = _speed <- val
I think you're confusing two different concepts: explicit fields and auto-properties. Under the hood, a property is more like a method than a field, although access/assignment are syntactically similar. The F# equivalent of your C# would be:
type Example() as this =
[<DefaultValue>] val mutable public speed: float32;
do this.speed <- 10.0f
Another way to implement this, which avoids the [<DefaultValue>] and imperative initialization, would be as follows (note the absence of default constructor on the first line):
type Example =
val mutable public speed : float32
new() = { speed = 10.0f }