Swift: obtain module at runtime? - swift

In Swift, at runtime, is it possible to know the name of the module code is running in?
I'd want something like (and this is totally imaginary code)
let moduleName: String = CompileTimeInfo.moduleName
Related.

You might take advantage of the fact that the module name is used as a namespace and debugPrint ing a type will be prefixed with the module name:
enum Test {}
var string: String = ""
debugPrint(Test.self, to: &string)
print("Module name: \(string.split(separator: ".").first ?? "")")
Note: the type must be defined in the actual module. So, wrap first three lines into a function and return the module name, done.

Riffing off of #CouchDeveloper's excellent answer, you can get the module name for an arbitrary Swift type. You can use this to get the module name of any arbitrary code, by creating a type for this purpose.
func moduleName(for type: Any.Type) -> String {
// parse module name from string that looks like "ModuleName.ClassName"
if let subSequence = String(reflecting: type.self).split(separator: ".").first {
return String(subSequence)
} else {
return ""
}
}
print(moduleName(for: String.self)) // -> Swift
enum Test {}
print(moduleName(for: Test.self)) // -> SwiftModuleNameExample
This can even be embedded into a protocol.
public protocol Module {}
extension Module {
static var name: String { moduleName(for: Self.self) }
}
class ThisModule: Module {}
print(ThisModule.name) // -> SwiftModuleNameExample
A macOS command-line Xcode project for this code lives here.

Related

Protocols, Structs, but no concrete type

Ok I have a protocol called Environment
protocol Environment {
var rootURL: String {get}
}
Then two structs:
struct Production: Environment {
var rootURL = "www.api.mybackend.com/v1"
}
struct Development: Environment {
var rootURL = "www.api.mydevelopmentbackend.com/v1"
}
A settings object with a function that retrieves the environment:
class Settings {
func getEnvironment<T>() -> T where T: Environment {
let environmentRaw = self.retreiveEnvironmentFromLocalStore()
switch environmentRaw {
case 0:
return Development() as! T
case 1:
return Production() as! T
default:
return Development() as! T
}
}
func retreiveEnvironmentFromLocalStore() -> Int {
//Realm, SQLLite, Core Date, I don't really care for this example.
//Let's just say it defaults to returning 1
}
}
I really want to keep moving in a Protocol Oriented Programming direction but now when I call this function on a settings object and try to use the rootURL property the compiler complains it can't figure out the type. So, to better my understanding and to maybe find a solution:
1) Why does it care about the type if I am accessing a property defined by a protocol that at the very least it knows the returning type conforms to?
2) Structs don't have inheritance. Should I define a base class and forget about generics?
3) Can I make my getEnvironment function better? I don't like force casting, it seems like a code smell.
4) Am I even using generics correctly here?
EDIT 1:
To be clear, I want one function that returns a struct that I know will have this property.
Am I even using generics correctly here?
No, I don't think so. You are saying that getEnvironment will return T which can be any type that the client code specifies, as long as it implements Environment. However, the implementation of the method doesn't do this. It will only return two kinds of Environments, and which type it returns is not determined by the client code. The type returned depends on what retreiveEnvironmentFromLocalStore returns. Hence, generics is not suitable in this case.
Since the type of environment it returns is decided by the implementation of the method, instead of the client code, you should make use of polymorphism here - make it return an Environment instead:
func getEnvironment() -> Environment {
let environmentRaw = self.retreiveEnvironmentFromLocalStore()
switch environmentRaw {
case 0:
return Development()
case 1:
return Production()
default:
return Development()
}
}
I really want to keep moving in a Protocol Oriented Programming direction
I suggest instead you try to move in a clear, understandable code direction, regardless of what the trendy orientation is.
Here's your function declaration:
func getEnvironment() -> T where T: Environment
This says that getEnvironment() will return an object of some type T, where T is deduced at compile time based on the code that calls getEnvironment().
What types could T be? It could be either Production or Development. For example, you could write:
let e: Production = Settings().getEnvironment()
This lets the compiler deduce that getEnvironment() returns a Production (which is an Environment) at this call site.
But there's a problem: getEnvironment() might try to return a Development anyway, based on the random number generator inside retreiveEnvironmentFromLocalStore. Then you'll get a crash at run time when it fails to cast Development to Production.
Why do you think getEnvironment() needs to be generic at all? Based on the code in your question, it shouldn't be.
import Foundation
protocol Environment {
var rootURL: String {get}
}
struct Production: Environment {
var rootURL = "www.api.mybackend.com/v1"
}
struct Development: Environment {
var rootURL = "www.api.mydevelopmentbackend.com/v1"
}
class Settings {
func getEnvironment() -> Environment {
let environmentRaw = self.retreiveEnvironmentFromLocalStore()
switch environmentRaw {
case 1: return Production()
default: return Development()
}
}
func retreiveEnvironmentFromLocalStore() -> Int {
return Int(arc4random())
}
}
let settings = Settings()
let e = settings.getEnvironment()
Style note: the Swift API Design Guidelines advise us to
Name functions and methods according to their side-effects
Those without side-effects should read as noun phrases, e.g. x.distance(to: y), i.successor().
Unless the methods in Settings have important side effects, better names would be environment() and rawEnvironmentFromLocalStore().

Swift: How to hold any possible instance of a generic type in a variable

The distillation of what I am trying to do is this:
public struct HolderOfWrappers
{
let anyWrappedItem: MyResource<Any>
}
public struct MyResource<A>
{
let wrappedItem : A
let convert: String -> A
}
func holdResource<A>( resource: MyResource<A> ) -> HolderOfWrappers
{
// Error on this line, A is not Any...
let wrapHolder : HolderOfWrappers = HolderOfWrappers( resource )
return wrapHolder
}
As it stands, this code produces the compiler error in the last holdResource method where I'm trying to build a HolderOfWrappers:
Cannot convert the expression's type 'MyResource<A>' to type '(anyWrappedItem: MyResource<Any>)'
Which is understandable as the code indicates HolderOfWrappers can only hold a MyResource built for Any type, not any possible type. What I'm really after with the HolderOfWrappers is something like this:
public struct HolderOfWrappers
{
let anyWrappedItem: MyResource<>
}
or even MyResource<*> - I am trying to say with this code that I'd like a variable that can hold any type of MyResource. If I try to use either syntax though, I get a compiler error that it expects a type.
I could just have anyWrappedItem by of type Any, but then you lose the type information for future use. I also do not want HolderOfWrappers to be generic (because then I'd just have the same problem later).
It's almost like I am trying to treat the generic type as a protocol for the anyWrappedItem storage variable, which will not work for other reasons...
I think you can do what you want by putting a generic parameter in your HolderOfWrappers init method. Basically, the init method just generates a new MyResource using the resource that you provide, like this:
public struct HolderOfWrappers {
let anyWrappedItem: MyResource<Any>
public init<A>(resource: MyResource<A>) {
self.anyWrappedItem = MyResource(wrappedItem: resource.wrappedItem, convert: resource.convert)
}
}
I think that will do what you want. I don't know if it will be slower since you are initializing an entirely new MyResource instead of just copying one.
At any rate, it makes it so that HolderOfWrappers itself is not generic and will fill anyWrappedItem with a MyResource<Any> that holds the same values as the resource that you pass in.
How about this
protocol Wrapper {}
public struct HolderOfWrappers {
let anyWrappedItem: MyResource<Wrapper>
}
public struct MyResource<A> {
let wrappedItem : A
let convert: String -> A
}
func holdResource( resource: MyResource<Wrapper>) -> HolderOfWrappers {
// Error on this line, A is not Any...
let wrapHolder : HolderOfWrappers = HolderOfWrappers(anyWrappedItem: resource)
return wrapHolder
}
of course the downside is you'd have to do extension A: Wrapper { } for any type A that you pass into MyResource.

Why do I have to pass arguments to classes in key-value form?

class NamedShape {
var numberOfSides: Int = 0
var name: String
init(name: String) {
self.name = name
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides named \(name)"
}
}
I have the following example class. To create a new instance, I do
let shape = NamedShape(name: "Test")
The arguments are captured by the init() function, right? However, if I do this:
let shape = NamedShape("Test")
I get a missing argument label error!
However, if I define a silly function like this:
func printInt(numberIn: Int) {
println(numberIn)
}
I can invoke it just fine using:
printInt(5)
However, if I attempt to invoke it with the arguments formatted in the way I create a class:
printInt(numberIn: 5)
I get an extraneous argument label error!
Help a swift noob understand. Why do I need to label class arguments, but I can't label function arguments? Why are functions and classes different this way? I'm sure there's something I'm missing.
Because initializer functions aren’t called with a function name, the parameter types and names are used to disambiguate among multiple init() functions. Thus, init() function parameters have external names by default.
You can explicitly opt out of default parameter names with an underscore:
init(_ name: String) {
self.name = name
}
init() functions are special cases and all parameters are required to have an external name.
https://developer.apple.com/library/ios/documentation/swift/conceptual/Swift_Programming_Language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-XID_306

Obtaining a string representation of a protocol dynamically

I'm looking for a way to obtain a protocol name dynamically from the protocol type, without having to use the #objc attribute in the protocol declaration.
I know that this works:
func keyForProtocol(aProtocol: Protocol) -> String {
return NSStringFromProtocol(aProtocol)
}
but only if the protocol has the #obj attribute:
#objc protocol Test {}
var key = keyForProtocol(Test.self) // Key contains "TestApp.Test"
however as soon as I remove the #objc attribute, compilation fails with this error:
'Test.Protocol' is not convertible to 'Protocol'
Is there any way to achieve that?
Note: the reason why I want to avoid #objc is that it doesn't allow usage of associated types (i.e. generics in protocol) - in those cases compilation fails with this error: Method cannot be marked #objc because the type of parameter xx cannot be represented in Objective-C
I recently found a solution by implementing the keyForProtocol method as follows:
func keyForProtocol<P>(aProtocol: P.Type) -> String {
return ("\(aProtocol)")
}
It works with any type, not just for protocols, but I'm ok with that.
Some examples from a playground:
protocol Test {}
keyForProtocol(Test.self) // Prints "__lldb_expr_92.Test"
class MyClass {}
keyForProtocol(MyClass.self) // Prints "__lldb_expr_92.MyClass"
keyForProtocol(Int.self) // Prints "Swift.Int"
keyForProtocol(UIView.self) // Prints "UIView"
As Antonio said:
let protocolDescription = "\(aProtocol)"
will return a (sometime strange) protocol name.
I finally completed my task converting back this string to a protocol with:
let protocolReference = NSProtocolFromString(protocolDescription)
This technique is perfect if you need to retrieve the protocol type from a generic parameter like in this example (a lightweight/homemade dependency manager):
class DependencyManager<T> {
private static func inject(_ aProtocol: T.Type) -> T {
let application = UIApplication.shared.delegate as! LMApplication
let dependencies = application.applicationDependencies
let protocolReference = NSProtocolFromString("\(aProtocol)")
let dependency = dependencies!.object(for: protocolReference)
return dependency! as! T
}
}
Usage:
let object: Protocol = DependencyManager.inject(Protocol.self)

Macros in Swift?

Does Swift currently support macros, or are there future plans to add support? Currently I'm scattering:
Log.trace(nil, function: __FUNCTION__, file: __FILE__, line: __LINE__)
In various places throughout my code.
In this case you should add a default value for the "macro" parameters.
Swift 2.2 and higher
func log(message: String,
function: String = #function,
file: String = #file,
line: Int = #line) {
print("Message \"\(message)\" (File: \(file), Function: \(function), Line: \(line))")
}
log("Some message")
Swift 2.1 and lower
func log(message: String,
function: String = __FUNCTION__,
file: String = __FILE__,
line: Int = __LINE__) {
print("Message \"\(message)\" (File: \(file.lastPathComponent), Function: \(function), Line: \(line))")
}
log("Some message")
This is what fatalError and assert functions do.
There are no other macros except the conditional compilation already mentioned in another answer.
The Apple docs state that:
Declare simple macros as global constants, and translate complex macros into functions.
You can still use #if/#else/#endif - but my feeling is that they will not introduce macro functions, the language simply doesn't need it.
Since XCode 7.3, the __FILE__ __FUNCTION__ and __LINE__ compile-time constants have become the nicer-looking #file #function and #line respectively.
Here is an updated Swift 2 answer.
func LogW(msg:String, function: String = #function, file: String = #file, line: Int = #line){
print("[WARNING]\(makeTag(function, file: file, line: line)) : \(msg)")
}
private func makeTag(function: String, file: String, line: Int) -> String{
let url = NSURL(fileURLWithPath: file)
let className = url.lastPathComponent ?? file
return "\(className) \(function)[\(line)]"
}
Example of use:
LogW("Socket connection error: \(error)")
lastPathComponent needs an NSURL, so I changed the above code to this:
func log(message: String,
function: String = __FUNCTION__,
file: String = __FILE__,
line: Int = __LINE__) {
let url = NSURL(fileURLWithPath: file)
print("Message \"\(message)\" (File: \(url.lastPathComponent ?? "?"), Function: \(function), Line: \(line))")
}
log("some message")
There is way to use macros on swift (but this used in Mixed of objective c and swift)
declare your macros into Project-name-Bridging-Header.h
#define YOUR_MACRO #"Description"
or create separate header file for macros "macros.h"
import this header "macros.h" in to your Bridging-Header.h file..
now just save your project your macros will came in swift file ..
if you don't wanna object c code on your swift project... just create dummy cocoa touch classes it will create bridging header then use my way...
Macros are evil, but sometimes you just need them. For example, I have
struct RegionEntity {
var id: Int!
}
And I want to place instances of this struct to Set. So I have to conform it to Hashable protocol.
extension RegionEntity: Hashable {
public var hashValue: Int {
return id
}
}
public func ==(first: RegionEntity, second: RegionEntity) -> Bool {
return first.id == second.id
}
Great. But what if I have dozens of such structs and the logic is the same? Maybe I can declare some protocol and conform it to Hashable implicitly. Let's check:
protocol Indexable {
var id: Int! { get }
}
extension Indexable {
var hashValue: Int {
return id
}
}
func ==(first: Indexable, second: Indexable) -> Bool {
return first.id == second.id
}
Well, it works. And now I'm gonna conform my struct to both protocols:
struct RegionEntity: Indexable, Hashable {
var id: Int!
}
Nope. I can't do that, because Equatable requires == operator with Self and there is no == operator for RegionEntity.
Swift forces me to copy-paste confirmation code for each struct and just change the name. With macro I could do that with only one line.
A macro proposal is going through Swift Evolution right now. This would allow you to define a custom type that could create a macro that can be evaluated at compile time, like the C stringify macro, for example.
https://forums.swift.org/t/se-0382-expression-macros/62090