Currently I'm working on my new App written with Swift 2.0. Today I faced two strange errors in Xcode beta 5. I'd love if someone with a previous beta version of Xcode can confirm if I'm right or not. I also could misunderstand something, so I'll appreciate any feedback.
Here is some example code that made me struggle a while:
// Frist bug
protocol SomeProtocol {
var someArray: [String] { get set } // #1 bug
}
extension SomeProtocol {
func someFunction(someString: String) {
self.someArray.append(someString) // #1: Immutable value of type '[String]' only has mutating members named 'append'
}
}
// Second bug
protocol SomeInterfaceProtocol {
var someBool: Bool { get set } // #2 bug
}
class SomeClass: SomeInterfaceProtocol {
var someBool: Bool = false
func returnInterface() -> SomeInterfaceProtocol {
return self
}
}
let someInstance = SomeClass()
// can't set the value
someInstance.returnInterface().someBool = true // #2: Cannot assign to property: function call returns immutable value
The first error can be solved if you add the modifier mutating before the extension func declaration like this:
mutating func someFunction(someString: String) {
I suspect that's a change in the language.
The other one puzzles me as well. At least, here's a work-around:
var c = someInstance.returnInterface()
c.someBool = true
I think the second one isn't a bug as well for the same reason that you can't modify an item in a dictionary directly, or that you can't change elem in for elem in array { ... }.
Something has to be saved to be able to change it. Because you're returning the protocol type, the compiler can't know whether it's a struct or a class, whereas if it's a struct the operation of changing it would have no effect because it's not persisted in any way and structs aren't passed by reference. That's why Thomas' workaround works. Maybe it'll work too if returnInterface returned a class instance, instead of the protocol type.
EDIT: Just tried it out: Indeed it works either if you return SomeClass instead of SomeInterfaceProtocol or if you change the protocol to a class protocol, as it can't be a struct
protocol SomeInterfaceProtocol : class {
var someBool: Bool { get set }
}
class SomeClass: SomeInterfaceProtocol {
var someBool: Bool = false
func returnInterface() -> SomeInterfaceProtocol {
return self
}
}
or
protocol SomeInterfaceProtocol {
var someBool: Bool { get set }
}
class SomeClass: SomeInterfaceProtocol {
var someBool: Bool = false
func returnInterface() -> SomeClass {
return self
}
}
both work
In Swift you can define an enum and give it a property via an associated value, e.g.:
protocol SizeEnum {
var length : Double? { get } // Length should be >= 0 - has to be an Optional for errors
}
enum SizesEnum : SizeEnum {
case Short(length : Double) // 0 <= length <= maxShort
case Long(length : Double) // length > maxShort
private static let maxShort = 1.0
var length : Double? {
get {
switch self {
case let .Short(length):
if length >= 0 && length <= SizesEnum.maxShort { // Need to error check every access
return length
}
case let .Long(length):
if length > SizesEnum.maxShort { // Need to error check every access
return length
}
}
return nil // There was an error
}
}
}
SizesEnum.Short(length: 0.5).length // [Some 0.5]
SizesEnum.Short(length: 2).length // nil
SizesEnum.Long(length: 2).length // [Some 2.0]
SizesEnum.Long(length: -1).length // nil
However this is not ideal because:
The error checking for the length parameter can only be done on access, you cannot intercept the init
The length parameter is surprisingly long winded
An alternative, which seems better to me, is to use a static factory, e.g.:
protocol SizeStruct {
var length : Double { get } // Length should be >= 0 - is *not* an Optional
}
struct SizesStruct : SizeStruct {
static func Short(length : Double) -> SizeStruct? {
if length >= 0 && length <= maxShort { // Check at creation only
return SizesStruct(length)
}
return nil
}
static func Long(length : Double) -> SizeStruct? {
if length > maxShort { // Check at creation only
return SizesStruct(length)
}
return nil
}
let length : Double
private static let maxShort = 1.0
private init(_ length : Double) {
self.length = length
}
}
SizesStruct.Short(0.5)?.length // [Some 0.5]
SizesStruct.Short(2)?.length // nil
SizesStruct.Long(2)?.length // [Some 2.0]
SizesStruct.Long(-1)?.length // nil
Given that the static factory solution is neater, when would I actually use an enum with values? Am I missing something? Is there a killer use case?
In response to drewag
For Optional other languages, e.g. Java and Scala, you use factories, the Java version is described here: http://docs.oracle.com/javase/8/docs/api/java/util/Optional.html the factory is the of method.
In Swift you would do something like:
class Opt { // Note only Some stores the value, not None
//class let None = Opt() - class variables not supported in beta 4!
class Some<T> : Opt {
let value : T
init(_ value : T) {
self.value = value
}
}
private init() {} // Stop any other ways of making an Opt
}
Opt.Some(1).value // 1
This is probably the optimal example for enum since no error checking is required, but even so the factory version is competitive. The Optional example is so straightforward you don't even need a factory, you just create the Somes directly. Note how None doesn't use any storage.
The Barcode example shows how much better the factory technique is; in practice not all collections of 4 Ints are a valid UPCA and not all Strings are a valid QR Code, therefore you need error checking which is painful with enums. Here is the factory version:
class Barcode { // Note seperate storage for each case
class UPCABarcode : Barcode {
let type : Int, l : Int, r : Int, check : Int
private init(type : Int, l : Int, r : Int, check : Int) {
(self.type, self.l, self.r, self.check) = (type, l, r, check)
}
}
class func UPCA(#type : Int, l : Int, r : Int, check : Int) -> UPCABarcode? {
if ok(type: type, l: l, r: r, check: check) {
return UPCABarcode(type: type, l: l, r: r, check: check)
}
return nil
}
class func QRCode(#s : String) -> Barcode? { // Have not expanded this case; use same pattern as UPCA
return Barcode()
}
private init() {} // Prevent any other types of Barcode
class func ok(#type : Int, l : Int, r : Int, check : Int) -> Bool {
return true // In practice has to check supported type, range of L and R, and if check digit is correct
}
}
Barcode.UPCA(type: 0, l: 1, r: 2, check: 3)
If you use the enum version of Barcode then every time you use a Barcode you have to check its validity because there is nothing to stop invalid barcodes. Whereas the factory version does the checking at creation. Note how Barcode has no storage and UPCA has custom storage. I didn't code QRCode because it uses the same design pattern as UPCA.
My impression is that the enum version looks great in tutorials but soon becomes painful in practice because of error handling.
I believe the biggest killer use case is Optional. It is built into the language, but an optional is simply an enum:
enum Optional<T> {
case None
case Some(T)
}
In this case, a member variable like value would not make sense because in the None case, there is literally no value.
Also, right out of the Swift tour:
enum Barcode {
case UPCA(Int, Int, Int, Int)
case QRCode(String)
}
With a struct, there would be a lot of wasted member variables and a confusing interface to model this kind of data.
I don't believe it makes sense to use an associated value for an enum if the same type is used for every case. In that case a member variable is cleaner. The focus of associated values is to more accurately model certain types of data. The most useful cases are ones where different instances of a type can have different data associated with them. This could potentially be done with subclasses but then one would need to downcast to access more specific variables and the declarations would be much more verbose. Enums are a concise way to represent this type of data.
Another example could be web requests:
struct NetRequest {
enum Method {
case GET
case POST(String)
}
var URL: String
var method: Method
}
var getRequest = NetRequest(URL: "http://drewag.me", method: .GET)
var postRequest = NetRequest(URL: "http://drewag.me", method: .POST("{\"username\": \"drewag\"}"))
When I think of "enum" I don't think of "factory" at all. Normally factories are for larger more complex class structures. Enums are supposed to be very small pieces of data with little logic.
I'm trying to do a simple comparison of a value received via an NSNotification, and an enumeration value. I have something that works, but I can't believe that this is the right way to be doing this. Basically the solution I ended up with was converting the NSNumber to an Int, and also getting the enum value's rawValue, wrapping it in an NSNumber and then getting the integerValue of that.
Everything else I tried resulted in compiler errors about not being able to convert between Uint 8 and Int or something similar.
observer = NSNotificationCenter.defaultCenter().addObserverForName(AVAudioSessionRouteChangeNotification, object: nil, queue: mainQueue) { notification in
println(AVAudioSessionRouteChangeReason.NewDeviceAvailable.toRaw())
if let reason = notification.userInfo[AVAudioSessionRouteChangeReasonKey!] as? NSNumber {
if (reason.integerValue == NSNumber(unsignedLong:AVAudioSessionRouteChangeReason.NewDeviceAvailable.toRaw()).integerValue) {
self.headphoneJackedIn = true;
} else if (reason.integerValue == NSNumber(unsignedLong:AVAudioSessionRouteChangeReason.OldDeviceUnavailable.toRaw()).integerValue) {
self.headphoneJackedIn = false;
}
self.updateHeadphoneJackLabel()
}
}
This should work:
if reason.integerValue == Int(AVAudioSessionRouteChangeReason.NewDeviceAvailable.rawValue) {
// ...
}
Remark: The AVAudioSessionRouteChangeReason enumeration uses UInt as raw value type, so
one could expect that this works without an explicit conversion:
if reason.unsignedIntegerValue == AVAudioSessionRouteChangeReason.NewDeviceAvailable.rawValue {
}
However, as of Xcode 6 beta 4, NSUInteger is mapped to Swift's Int in OS X and iOS
system frameworks, which means that both integerValue and unsignedIntegerValue return an Int,
and an explicit conversion is needed in any case.
Alternatively, you could create an enumeration value from the number (as already suggested by #ColinE
in a comment) and then use switch case:
if let r = AVAudioSessionRouteChangeReason(rawValue: UInt(reason.integerValue)) {
switch r {
case .NewDeviceAvailable:
// ...
case .OldDeviceUnavailable:
// ...
default:
// ...
}
} else {
println ("Other reason")
}
For the same reason as above, an explicit UInt conversion is necessary here as well.
How should bit fields be declared and used in Swift?
Declaring an enum like this does work, but trying to OR 2 values together fails to compile:
enum MyEnum: Int
{
case One = 0x01
case Two = 0x02
case Four = 0x04
case Eight = 0x08
}
// This works as expected
let m1: MyEnum = .One
// Compiler error: "Could not find an overload for '|' that accepts the supplied arguments"
let combined: MyEnum = MyEnum.One | MyEnum.Four
I looked at how Swift imports Foundation enum types, and it does so by defining a struct that conforms to the RawOptionSet protocol:
struct NSCalendarUnit : RawOptionSet {
init(_ value: UInt)
var value: UInt
static var CalendarUnitEra: NSCalendarUnit { get }
static var CalendarUnitYear: NSCalendarUnit { get }
// ...
}
And the RawOptionSet protocol is:
protocol RawOptionSet : LogicValue, Equatable {
class func fromMask(raw: Self.RawType) -> Self
}
However, there is no documentation on this protocol and I can't figure out how to implement it myself. Moreover, it's not clear if this is the official Swift way of implementing bit fields or if this is only how the Objective-C bridge represents them.
You can build a struct that conforms to the RawOptionSet protocol, and you'll be able to use it like the built-in enum type but with bitmask functionality as well. The answer here shows how:
Swift NS_OPTIONS-style bitmask enumerations.
Updated for Swift 2/3
Since swift 2, a new solution has been added as "raw option set" (see: Documentation), which is essentially the same as my original response, but using structs that allow arbitrary values.
This is the original question rewritten as an OptionSet:
struct MyOptions: OptionSet
{
let rawValue: UInt8
static let One = MyOptions(rawValue: 0x01)
static let Two = MyOptions(rawValue: 0x02)
static let Four = MyOptions(rawValue: 0x04)
static let Eight = MyOptions(rawValue: 0x08)
}
let m1 : MyOptions = .One
let combined : MyOptions = [MyOptions.One, MyOptions.Four]
Combining with new values can be done exactly as Set operations (thus the OptionSet part), .union, likewise:
m1.union(.Four).rawValue // Produces 5
Same as doing One | Four in its C-equivalent. As for One & Mask != 0, can be specified as a non-empty intersection
// Equivalent of A & B != 0
if !m1.intersection(combined).isEmpty
{
// m1 belongs is in combined
}
Weirdly enough, most of the C-style bitwise enums have been converted to their OptionSet equivalent on Swift 3, but Calendar.Compontents does away with a Set<Enum>:
let compontentKeys : Set<Calendar.Component> = [.day, .month, .year]
Whereas the original NSCalendarUnit was a bitwise enum. So both approaches are usable (thus the original response remains valid)
Original Response
I think the best thing to do, is to simply avoid the bitmask syntax until the Swift devs figure out a better way.
Most of the times, the problem can be solved using an enum and and a Set
enum Options
{
case A, B, C, D
}
var options = Set<Options>(arrayLiteral: .A, .D)
An and check (options & .A) could be defined as:
options.contains(.A)
Or for multiple "flags" could be:
options.isSupersetOf(Set<Options>(arrayLiteral: .A, .D))
Adding new flags (options |= .C):
options.insert(.C)
This also allows for using all the new stuff with enums: custom types, pattern matching with switch case, etc.
Of course, it doesn't have the efficiency of bitwise operations, nor it would be compatible with low level things (like sending bluetooth commands), but it's useful for UI elements that the overhead of the UI outweighs the cost of the Set operations.
They showed how to do this in one of the WWDC videos.
let combined = MyEnum.One.toRaw() | MyEnum.Four.toRaw()
Note that combined will be Int type and will actually get a compiler error if you specify let combined: MyEnum. That is because there is no enum value for 0x05 which is the result of the expression.
I think maybe some of the answers here are outdated with overcomplicated solutions? This works fine for me..
enum MyEnum: Int {
case One = 0
case Two = 1
case Three = 2
case Four = 4
case Five = 8
case Six = 16
}
let enumCombined = MyEnum.Five.rawValue | MyEnum.Six.rawValue
if enumCombined & MyEnum.Six.rawValue != 0 {
println("yay") // prints
}
if enumCombined & MyEnum.Five.rawValue != 0 {
println("yay again") // prints
}
if enumCombined & MyEnum.Two.rawValue != 0 {
println("shouldn't print") // doesn't print
}
If you don't need to interoperate with Objective-C and just want the syntax of bit masks in Swift, I've written a simple "library" called BitwiseOptions that can do this with regular Swift enumerations, e.g.:
enum Animal: BitwiseOptionsType {
case Chicken
case Cow
case Goat
static let allOptions = [.Chicken, .Cow, .Goat]
}
var animals = Animal.Chicken | Animal.Goat
animals ^= .Goat
if animals & .Chicken == .Chicken {
println("Chick-Fil-A!")
}
and so on. No actual bits are being flipped here. These are set operations on opaque values. You can find the gist here.
#Mattt's very famous "NSHipster" has an extensive detailed description of the RawOptionsSetType : http://nshipster.com/rawoptionsettype/
It includes a handy Xcode snipped:
struct <# Options #> : RawOptionSetType, BooleanType {
private var value: UInt = 0
init(_ value: UInt) { self.value = value }
var boolValue: Bool { return value != 0 }
static func fromMask(raw: UInt) -> <# Options #> { return self(raw) }
static func fromRaw(raw: UInt) -> <# Options #>? { return self(raw) }
func toRaw() -> UInt { return value }
static var allZeros: <# Options #> { return self(0) }
static func convertFromNilLiteral() -> <# Options #> { return self(0) }
static var None: <# Options #> { return self(0b0000) }
static var <# Option #>: <# Options #> { return self(0b0001) }
// ...
}
You have to use .toRaw() after each member:
let combined: Int = MyEnum.One.toRaw() | MyEnum.Four.toRaw()
will work. Because as it is you're just trying to assign "One" which is a MyEnum type, not an integer. As Apple's documentation says:
“Unlike C and Objective-C, Swift enumeration members are not assigned a default integer value when they are created. In the CompassPoints example, North, South, East and West do not implicitly equal 0, 1, 2 and 3. Instead, the different enumeration members are fully-fledged values in their own right, with an explicitly-defined type of CompassPoint.”
so you have to use raw values if you want the members to represent some other type, as described here:
Enumeration members can come prepopulated with default values (called raw values), which are all of the same type. The raw value for a particular enumeration member is always the same. Raw values can be strings, characters, or any of the integer or floating-point number types. Each raw value must be unique within its enumeration declaration. When integers are used for raw values, they auto-increment if no value is specified for some of the enumeration members. Access the raw value of an enumeration member with its toRaw method.
I use the following I need the both values I can get, rawValue for indexing arrays and value for flags.
enum MyEnum: Int {
case one
case two
case four
case eight
var value: UInt8 {
return UInt8(1 << self.rawValue)
}
}
let flags: UInt8 = MyEnum.one.value ^ MyEnum.eight.value
(flags & MyEnum.eight.value) > 0 // true
(flags & MyEnum.four.value) > 0 // false
(flags & MyEnum.two.value) > 0 // false
(flags & MyEnum.one.value) > 0 // true
MyEnum.eight.rawValue // 3
MyEnum.four.rawValue // 2
This worked for me.
1 << 0 //0000
1 << 1 //0010
1 << 2 //0100
1 << 3 //1000
enum Collision: Int {
case Enemy, Projectile, Debris, Ground
func bitmask() -> UInt32 {
return 1 << self.rawValue
}
}
I'm taking a guess that something like this is how they are modeling enum options in Foundation:
struct TestOptions: RawOptionSet {
// conform to RawOptionSet
static func fromMask(raw: UInt) -> TestOptions {
return TestOptions(raw)
}
// conform to LogicValue
func getLogicValue() -> Bool {
if contains([1, 2, 4], value) {
return true
}
return false
}
// conform to RawRepresentable
static func fromRaw(raw: UInt) -> TestOptions? {
if contains([1, 2, 4], raw) {
return TestOptions(raw)
}
return nil
}
func toRaw() -> UInt {
return value
}
// options and value
var value: UInt
init(_ value: UInt) {
self.value = value
}
static var OptionOne: TestOptions {
return TestOptions(1)
}
static var OptionTwo: TestOptions {
return TestOptions(2)
}
static var OptionThree: TestOptions {
return TestOptions(4)
}
}
let myOptions = TestOptions.OptionOne | TestOptions.OptionThree
println("myOptions: \(myOptions.toRaw())")
if (myOptions & TestOptions.OptionOne) {
println("OPTION ONE is in there")
} else {
println("nope, no ONE")
}
if (myOptions & TestOptions.OptionTwo) {
println("OPTION TWO is in there")
} else {
println("nope, no TWO")
}
if (myOptions & TestOptions.OptionThree) {
println("OPTION THREE is in there")
} else {
println("nope, no THREE")
}
let nextOptions = myOptions | TestOptions.OptionTwo
println("options: \(nextOptions.toRaw())")
if (nextOptions & TestOptions.OptionOne) {
println("OPTION ONE is in there")
} else {
println("nope, no ONE")
}
if (nextOptions & TestOptions.OptionTwo) {
println("OPTION TWO is in there")
} else {
println("nope, no TWO")
}
if (nextOptions & TestOptions.OptionThree) {
println("OPTION THREE is in there")
} else {
println("nope, no THREE")
}
...where myOptions and nextOptions are of type TestOptions - I'm not exactly sure how fromMask() and getLogicValue() are supposed to act here (I just took some best guesses), maybe somebody could pick this up and work it out?
If you want bitfield in Swift, then enum is the wrong way. Better just do like this
class MyBits {
static let One = 0x01
static let Two = 0x02
static let Four = 0x04
static let Eight = 0x08
}
let m1 = MyBits.One
let combined = MyBits.One | MyBits.Four
You don't really need the class/static wrapper, but I include it as a kind of pseudo namespace.
Do bitwise operation using raw value then create a new enum object using the result.
let mask = UIViewAutoresizing(rawValue: UIViewAutoresizing.FlexibleWidth.rawValue|UIViewAutoresizing.FlexibleHeight.rawValue)
self.view.autoresizingMask = mask
Here's something I put together to try to make a Swift enum that resembles to some extent a C# flags-style enum. But I'm just learning Swift, so this should only be considered to be "proof of concept" code.
/// This EnumBitFlags protocol can be applied to a Swift enum definition, providing a small amount
/// of compatibility with the flags-style enums available in C#.
///
/// The enum should be defined as based on UInt, and enum values should be defined that are powers
/// of two (1, 2, 4, 8, ...). The value zero, if defined, should only be used to indicate a lack of
/// data or an error situation.
///
/// Note that with C# the enum may contain a value that does not correspond to the defined enum
/// constants. This is not possible with Swift, it enforces that only valid values can be set.
public protocol EnumBitFlags : RawRepresentable, BitwiseOperations {
var rawValue : UInt { get } // This provided automatically by enum
static func createNew(_ rawValue : UInt) -> Self // Must be defined as some boiler-plate code
}
/// Extension methods for enums that implement the EnumBitFlags protocol.
public extension EnumBitFlags {
// Implement protocol BitwiseOperations. But note that some of these operators, especially ~,
// will almost certainly result in an invalid (nil) enum object, resulting in a crash.
public static func & (leftSide: Self, rightSide: Self) -> Self {
return self.createNew(leftSide.rawValue & rightSide.rawValue)
}
public static func | (leftSide: Self, rightSide: Self) -> Self {
return self.createNew(leftSide.rawValue | rightSide.rawValue)
}
public static func ^ (leftSide: Self, rightSide: Self) -> Self {
return self.createNew(leftSide.rawValue ^ rightSide.rawValue)
}
public static prefix func ~ (x: Self) -> Self {
return self.createNew(~x.rawValue)
}
public static var allZeros: Self {
get {
return self.createNew(0)
}
}
// Method hasFlag() for compatibility with C#
func hasFlag<T : EnumBitFlags>(_ flagToTest : T) -> Bool {
return (self.rawValue & flagToTest.rawValue) != 0
}
}
This shows how it can be used:
class TestEnumBitFlags {
// Flags-style enum specifying where to write the log messages
public enum LogDestination : UInt, EnumBitFlags {
case none = 0 // Error condition
case systemOutput = 0b01 // Logging messages written to system output file
case sdCard = 0b10 // Logging messages written to SD card (or similar storage)
case both = 0b11 // Both of the above options
// Implement EnumBitFlags protocol
public static func createNew(_ rawValue : UInt) -> LogDestination {
return LogDestination(rawValue: rawValue)!
}
}
private var _logDestination : LogDestination = .none
private var _anotherEnum : LogDestination = .none
func doTest() {
_logDestination = .systemOutput
assert(_logDestination.hasFlag(LogDestination.systemOutput))
assert(!_logDestination.hasFlag(LogDestination.sdCard))
_anotherEnum = _logDestination
assert(_logDestination == _anotherEnum)
_logDestination = .systemOutput | .sdCard
assert(_logDestination.hasFlag(LogDestination.systemOutput) &&
_logDestination.hasFlag(LogDestination.sdCard))
/* don't do this, it results in a crash
_logDestination = _logDestination & ~.systemOutput
assert(_logDestination == .sdCard)
*/
_logDestination = .sdCard
_logDestination |= .systemOutput
assert(_logDestination == .both)
}
}
Suggestions for improvement are welcome.
EDIT: I've given up on this technique myself, and therefore obviously can't recommend it anymore.
The big problem is that Swift demands that rawValue must match one of the defined enum values. This is OK if there are only 2 or 3 or maybe even 4 flag bits - just define all of the combination values in order to make Swift happy. But for 5 or more flag bits it becomes totally crazy.
I'll leave this posted in case someone finds it useful, or maybe as a warning of how NOT to do it.
My current solution to this situation is based on using a struct instead of enum, together with a protocol and some extension methods. This works much better. Maybe I'll post it someday when I'm more sure that that isn't also isn't going to backfire on me.
Task
Get all flags from flags_combination. Each flag and flags_combination are integers. flags_combination = flag_1 | flags_2
Details
Xcode 11.2.1 (11B500), Swift 5.1
Solution
import Foundation
protocol FlagPrototype: CaseIterable, RawRepresentable where RawValue == Int {}
extension FlagPrototype {
init?(rawValue: Int) {
for flag in Self.allCases where flag.rawValue == rawValue {
self = flag
return
}
return nil
}
static func all(from combination: Int) -> [Self] {
return Self.allCases.filter { return combination | $0.rawValue == combination }
}
}
Usage
enum Flag { case one, two, three }
extension Flag: FlagPrototype {
var rawValue: Int {
switch self {
case .one: return 0x1
case .two: return 0x2
case .three: return 0x4
}
}
}
var flags = Flag.two.rawValue | Flag.three.rawValue
let selectedFlags = Flag.all(from: flags)
print(selectedFlags)
if selectedFlags == [.two, .three] { print("two | three") }
Consider I have the following classes:
/// File classes.d
class C {
string type() { return "C"; };
}
class C1 : C {
override string type() { return "C1"; };
}
class C2 : C {
override string type() { return "C1"; };
}
Now I want to implement a factory somewhere else, like:
/// File factory.d
module factory;
import std.functional;
import std.stdio;
void main() {
mixin(import("classes.d"));
auto c = cast(typeof(mixin("C1"))) Object.factory("C1");
writeln(c.type());
}
The compiler (dmd 2.058) says me:
factory.d(7): Error argument C1 to typeof is not an expression
I know the following line compiles well:
auto c = cast(C1) Object.factory("classes.C1");
but this requires me to know the type (C1) at compile time. I want to get the type at runtime (like a string).
mixin(`auto c = cast(typeof(C1)) Object.factory("C1");`)
I don't understand you question, I think:
You want to cast dynamically at runtime to a given type? This is not possible in a statically typed language! What you can do is, passing your classes (or whatever) around as void* and using a switch … case to cast it to the needed type (you can also use std.variant, which is maybe the better way, but I've never used it) and then calling different functions (templated functions):
final switch(which_type) {
case "C1": foo(cast(C1)bar); break;
case "C2": foo(cast(C2)bar); break;
}
void foo(T)(T a) {
}
You can also generate the switch case at compile-time:
final switch(which_type) {
foreach(i; TypeTuple("C1", "C2")) {
case i: foo(mixin(`cast(` ~ i ~ `)bar`); break;
}
}
If you just wanna get the string of the type typeof(bar).stringof will give you the type of bar as string (but this is already known at compile time).
Mixins are a compile time artifact and can only be used at compile time. typeof can only be used at compile time. D is a statically typed language, and all types must be known at compile time.
You can have a reference of a base class type which refers to a derived class instance, so something like this is possible:
C makeC(string type)
{
switch(type)
{
case "C": return new C;
case "C1": return new C1;
case "C2": return new C2;
default: throw new Exception(format("%s is not a C", tye));
}
}
C c = makeC("C1");
There's also std.variant which can be used to hold different types (it uses a union internally).
But you can't decide what the type of a variable is going to be at runtime, because D is statically typed.