Typed symbolic constant strings

I'm trying to create a few sets of symbolic constants using the technique used by Notification.Name (which typealiases to NSNotification.Name):

public struct Name : RawRepresentable, Equatable, Hashable {
	public private(set) var rawValue: String
	public init(rawValue: String) {
		self.rawValue = rawValue
	}
	
	public var hashValue: Int {
		return self.rawValue.hashValue
	}
	
	public static func ==(lhs: Name, rhs: Name) -> Bool {
		return lhs.rawValue == rhs.rawValue
	}
}

The thing I'd like to do is implement the Name struct once, and then create new names for that type that are not considered compatible by the compiler. I thought typealias did that, but I guess not. Is there any way I can create separate types that are all functionally identical to Name above without duplicating the entire definition?

You can remove the manual implementations of hashValue and ==, since those will be synthesized by the compiler as of Swift 4.1 (keep the conformances in the conformance list).

Beyond that, I don't think there's much you can do to reduce it further. You still need to declare the rawValue property and initializer explicitly. There have been various discussions on these forums about some kind of newtype functionality that would create aliases that are distinct types, but nothing fully proposed or implemented yet.

If you have a lot of these, you could consider a codegen approach that uses gyb from the Swift repo, or another solution like Sourcery.

1 Like

Thank you, that helps a lot. +1 for the newType idea, that would be really nice.

There's a library implementation of newType called Tagged, but it's not as nice as actual language support would be.

1 Like
typedef NSString *NSNotificationName NS_EXTENSIBLE_STRING_ENUM;

If you define a new type in Objective-C like

typedef NSString *NSNotificationName1 NS_EXTENSIBLE_STRING_ENUM;

then is Swift, the type is

struct NSNotificationName1: Hashable, Equatable, RawRepresentable {

    public init(_ rawValue: String)

    public init(rawValue: String)
}

It is NS_EXTENSIBLE_STRING_ENUM that makes it happens. But I don't know why UIKit it will be NSNotification.Name.
NS_EXTENSIBLE_STRING_ENUM and NS_TYPED_EXTENSIBLE_ENUM do the same thing.
In Objective-C

typedef NSString *NSNotificationName1 NS_STRING_ENUM;

In Swift

struct NSNotificationName1: Hashable, Equatable, RawRepresentable {

    public init(rawValue: String)
}

NS_STRING_ENUM and NS_TYPED_ENUM do the same thing.

2 Likes