Is there a possibility to apply the same dart extension to multiple enums? Here is my enum and extension.
enum Currency {
EUR, INR, USD, CNY, JPY, GBP
}
extension ParseToString on Currency {
String toShortString() {
return this.toString().split('.').last;
}
}
Is it possible to make it like
enum InvoiceStatus {
DRAFT, SENT, PAID, PARTIALLY_PAID
}
extension ParseToString on Currency, InvoiceStatus {
String toShortString() {
return this.toString().split('.').last;
}
}
While there isn't a way to add an extension to multiple enums, since dart 2.14 all enums extends a common interface: Enum. That allows you to add an extensions to all enums:
extension on Enum {
String toShortString() {
return this.toString().split('.').last;
}
}
after so you can use .toShortString() to any enum object.
Related
I am trying to create a protocol with default implementation that returns enum itself as string. But not able to find the correct syntax.
This is the code I tried so far, but it is not taking default implementation
protocol TestSelf {
static var desc: String { get set }
}
extension TestSelf {
get {
static var desc: String {
String(describing: self)
}
set {
print(\(new value))
}
}
enum Test: TestSelf { }
Access
print(Test.desc)
Asking me to implement the desc in the enum saying 'static var' declaration requires an initializer expression or an explicitly stated getter. I don't want to initialize it again. It should work with Default Implementation.
Ask:
At all places I don't need to write
String(describing: Test.self)
instead I can directly use
Test.desc
I think you want something like this (this is playground code):
protocol SelfDescriber {
static var descriptionOfSelf: String {get}
}
extension SelfDescriber {
static var descriptionOfSelf: String {
String(describing: Self.self)
}
}
enum Test: SelfDescriber {}
print(Test.descriptionOfSelf) // "Test"
Is it possible to have a function available only when the property of a parameter meets a certain condition? For example, by using the where keyword? I gave an example of the idea below.
struct ASN1 {
enum Types: UInt8 {
case constructed
case primitive
}
class Tag {
let type: Types
}
class Encoder {
func enter(tag: ASN1.Tag) where tag.type == .constructed {
// Function only available when tag property type is .constructed
}
}
}
I just stuck in swift's document that explain how "NSStringCompareOptions" works. Just some newb questions.
struct NSStringCompareOptions : OptionSetType {
init(rawValue rawValue: UInt)
static var CaseInsensitiveSearch: NSStringCompareOptions { get }
static var LiteralSearch: NSStringCompareOptions { get }
static var BackwardsSearch: NSStringCompareOptions { get }
static var AnchoredSearch: NSStringCompareOptions { get }
static var NumericSearch: NSStringCompareOptions { get }
static var DiacriticInsensitiveSearch: NSStringCompareOptions { get }
static var WidthInsensitiveSearch: NSStringCompareOptions { get }
static var ForcedOrderingSearch: NSStringCompareOptions { get }
static var RegularExpressionSearch: NSStringCompareOptions { get }
}
and this struct contains "init" in it, when I call NSStringCompareOptions()
Why it allows the init method "rawValue" to be omitted?
and another question is that I know
NSStringCompareOptions()
is the new version as
NSStringCompareOptions.allZero
and it means "no options"
so what's the different between both below?
NSStringCompareOptions()
NSStringCompareOptions(rawValue:0)
Thank you very much for helping me.
For a better understanding, you should look at the definition of OptionSetType, which is the protocol which NSStringCompareOptions conforms to.
In addition to the basic protocol definition, you will find some extensions:
extension OptionSetType where RawValue : BitwiseOperationsType {
/// Create an empty instance.
///
/// - Equivalent to `[] as Self`
public convenience init()
...
}
And the SetAlgebraType protocol which OptionSetType conforms to:
extension SetAlgebraType {
/// Creates the set containing all elements of `sequence`.
public convenience init<S : SequenceType where S.Generator.Element == Element>(_ sequence: S)
...
}
The fact that these methods are in protocol extensions indicates that they have default implementations which are automatically provided.
You can read more about option sets in Using Swift with Cocoa and Objective-C.
Both are same NSStringCompareOptions() and NSStringCompareOptions(rawValue:0)
There is no deffernce. you can used any of those.
Good Luck and Happy coding
I want to be able to have the classes which have a static property (field) which is either inherited from the base class or "mixed" from a protocol. And every class should have it's own implementation of that property. Is it possible? Preferably, it to be immutable.
class C1 {
static let stProperty = "my prorepty1"
}
class C2 {
static let stProperty = "my prorepty2"
}
It's possible, but it's really hard to make this useful in Swift. How do you plan to refer to this property? Let's start with a super-simple implementation:
protocol SomeProtocol {
static var prop: String { get }
}
class C1: SomeProtocol {
static let prop = "This is One"
}
Great. So now I want a function that uses this:
func useProp(x: SomeProtocol) -> String {
return x.prop
// 'SomeProtocol' does not have a member named 'prop'
}
That doesn't work. x is an instance, but I want the type.
// Accessing members of protocol type value 'SomeProtocol.Type' is unimplemented
func useProp(x: SomeProtocol.Type) -> String {
return x.prop
}
This is probably how it will work some day given the word "unimplemented." But it doesn't work today.
func useProp(x: SomeProtocol) -> String {
// Accessing members of protocol type value 'SomeProtocol.Type' is unimplemented
return x.dynamicType.prop
}
Same thing.
Today, you really have to hang this on the object itself and not use static or class:
protocol SomeProtocol {
var prop: String { get }
}
class C1: SomeProtocol {
let prop = "This is One"
}
func useProp(x: SomeProtocol) -> String {
return x.prop
}
That's not so terrible in many cases, since the value for the class is probably also the value for any given instance of the class. And it's really all we can do today.
Of course your problem might be that you don't have an instance yet and you need this information to build an instance. That's really hard today and you should probably rethink your design. You'll generally have to use some other pattern like a Builder. See Generic Types Collection for more.
Now you also said:
or "mixed" from a protocol
I wouldn't say "mixed" here. If you really mean this like a Ruby "mixin", there is no such thing in Swift today. Swift folks often refer to this feature as "default implementation," and it's not currently possible (though I do expect it to come eventually). The only thing you can do in the protocol is say that the implementor has to provide this method somehow. You can't provide it for them.
Sure you can do that with a protocol:
protocol SomeProtocol {
static var foo: String { get }
}
class One: SomeProtocol {
class var foo: String {
get {
return "This is One"
}
}
}
Btw I agree with Rob Napier below that this is a bit off a oddball feature. I do think there are probably use-cases for it, but I also think those can be better implemented with other language features
protocol P {
class var stProperty: String { get }
}
class C1 {
class var stProperty: String {
return = "my property1"
}
}
class C2 {
class var stProperty: String {
return = "my property2"
}
}
Usage:
C2.prop //"my property2"
If you try:
C2.prop = "new value" //"cannot assign to the result of this expression"
I have extensions for about 20 enums which look like this:
extension CurrencyValue : JSONDecodable {
static func create(rawValue: String) -> CurrencyValue {
if let value = CurrencyValue(rawValue: rawValue) {
return value
}
return .unknown
}
static func decode(j: JSONValue) -> CurrencyValue? {
return CurrencyValue.create <^> j.value()
}
}
extension StatusValue : JSONDecodable {
static func create(rawValue: String) -> StatusValue {
if let value = StatusValue(rawValue: rawValue) {
return value
}
return .unknown
}
static func decode(j: JSONValue) -> StatusValue? {
return StatusValue.create <^> j.value()
}
}
They are almost the same except the enum type name and I have 20 of them - thats obviously very stupid. Does anybody have an idea how to reduce them to one, maybe by using generics? I have no idea at the moment.
UPDATE
The enums are as simple as this:
enum CurrencyValue : String {
case EUR = "EUR"
case unknown = "unknown"
}
enum StatusValue : String {
case ok = "ok"
case pending = "pending"
case error = "error"
case unknown = "unknown"
}
And lets assume the following:
Every ENUM has the .unknown case
I need to exchange the enum type in the extension with something generic.
There must be some trick to not implement the same extension multiple times and just alter the type.
UPDATE
As it s stated by Gregory Higley below I use the JSON lib Argo. You can read about the operators there.
The essence of your question is that you want to avoid writing boilerplate code for all of these enumerations when implementing Argo's JSONDecodable. It looks like you've also added a create method, which is not part of the type signature of JSONDecodable:
public protocol JSONDecodable {
typealias DecodedType = Self
class func decode(JSONValue) -> DecodedType?
}
Unfortunately this cannot be done. Swift protocols are not mixins. With the exception of operators, they cannot contain any code. (I really hope this gets "fixed" in a future update of Swift. Overridable default implementations for protocols would be amazing.)
You can of course simplify your implementation in a couple of ways:
As Tony DiPasquale suggested, get rid of .unknown and use optionals. (Also, you should have called this .Unknown. The convention for Swift enumeration values is to start them with a capital letter. Proof? Look at every enumeration Apple has done. I can't find a single example where they start with a lower case letter.)
By using optionals, your create is now just a functional alias for init? and can be implemented very simply.
As Tony suggested, create a global generic function to handle decode. What he did not suggest, though he may have assumed it was implied, was to use this to implement JSONDecodable.decode.
As a meta-suggestion, use Xcode's Code Snippets functionality to create a snippet to do this. Should be very quick.
At the asker's request, here's a quick implementation from a playground. I've never used Argo. In fact, I'd never heard of it until I saw this question. I answered this question simply by applying what I know about Swift to an examination of Argo's source and reasoning it out. This code is copied directly from a playground. It does not use Argo, but it uses a reasonable facsimile of the relevant parts. Ultimately, this question is not about Argo. It is about Swift's type system, and everything in the code below validly answers the question and proves that it is workable:
enum JSONValue {
case JSONString(String)
}
protocol JSONDecodable {
typealias DecodedType = Self
class func decode(JSONValue) -> DecodedType?
}
protocol RawStringInitializable {
init?(rawValue: String)
}
enum StatusValue: String, RawStringInitializable, JSONDecodable {
case Ok = "ok"
case Pending = "pending"
case Error = "error"
static func decode(j: JSONValue) -> StatusValue? {
return decodeJSON(j)
}
}
func decodeJSON<E: RawStringInitializable>(j: JSONValue) -> E? {
// You can replace this with some fancy Argo operators,
// but the effect is the same.
switch j {
case .JSONString(let string): return E(rawValue: string)
default: return nil
}
}
let j = JSONValue.JSONString("ok")
let statusValue = StatusValue.decode(j)
This is not pseudocode. It's copied directly from a working Xcode playground.
If you create the protocol RawStringInitializable and have all your enumerations implement it, you will be golden. Since your enumerations all have associated String raw values, they implicitly implement this interface anyway. You just have to make the declaration. The decodeJSON global function uses this protocol to treat all of your enumerations polymorphically.
If you can provide an example of an enum as well it might be easier to see what could be improved.
Just looking at this I would say you might want to consider removing .unknown from all the enums and just have the optional type represent an .unknown value with .None. If you did this you could write:
extension StatusValue: JSONDecodable {
static func decode(j: JSONValue) -> StatusValue? {
return j.value() >>- { StatusValue(rawValue: $0) }
}
}
No need for all the create functions now. That will cut down on a lot of the duplication.
Edit:
You could possibly use Generics. If you create a protocol DecodableStringEnum like so:
protocol DecodableStringEnum {
init?(rawValue: String)
}
Then make all your enums conform to it. You don't have to write any more code because that init comes with raw value enums.
enum CreatureType: String, DecodableStringEnum {
case Fish = "fish"
case Cat = "cat"
}
Now write a global function to handle all those cases:
func decodeStringEnum<A: DecodableStringEnum>(key: String, j: JSONValue) -> A? {
return j[key]?.value() >>- { A(rawValue: $0) }
}
Finally, in Argo you can have your creature decode function look like this:
static func decode(j: JSONValue) -> Creature? {
return Creature.create
<^> j <| "name"
<*> decodeStringEnum("type", j)
<*> j <| "description"
}
For anyone else coming along, the most up to date answer is to follow: https://github.com/thoughtbot/Argo/blob/td-decode-enums/Documentation/Decode-Enums.md
Essentially, for the enums
enum CurrencyValue : String {
case EUR = "EUR"
case unknown = "unknown"
}
enum StatusValue : String {
case ok = "ok"
case pending = "pending"
case error = "error"
case unknown = "unknown"
}
You only need to do
extension CurrencyValue: Decodable {}
extension StatusValue: Decodable {}
Also as it seems to have been pointed out repeatedly, if you just get rid of the .Unknown field and instead use optionals you can use the builtin support for enums as a RawRepresentable type.
See also: https://github.com/thoughtbot/Argo/blob/master/Argo/Extensions/RawRepresentable.swift for the implementation that makes this possible.