In a class, I defined a private constant, I try to use the constant as a default value of parameter of a function:
class Foo {
// instance variable
private let DefaultValue = 10
// Compiler error: Cannot use instance member 'DefaultValue' as a default parameter
public func doTask(amount: Int = DefaultValue) {
...
}
}
But I get compiler error: Cannot use instance member 'DefaultValue' as a default parameter
.
Then, I also tried declare DefaultValue
as private static
:
class Foo {
// static variable
private static let DefaultValue = 10
// Compiler error: Static let 'DefaultValue' is private and cannot be referenced from a default argument value
public func doTask(amount: Int = DefaultValue) {
...
}
}
But I get new compiler error: Static let 'DefaultValue' is private and cannot be referenced from a default argument value
I need to keep DefaultValue
private to this class & I would like to assign default value to the parameter of function with a private variable, whether this is achievable in Swift 4?
I don't think that is possible. The default value is inserted at the calling site, and therefore needs to be public, see also
Access control in swift 4.
A possible workaround would be to make the parameter optional,
and substitute nil
by the default value locally:
class Foo {
private static let DefaultValue = 10
public func doTask(amount: Int? = nil) {
let amount = amount ?? Foo.DefaultValue
// ...
}
}
A somewhat complicated, but workable, solution, for hiding the default value you want within your class is to use a protocol and a conforming struct whose intimate details are known only by the file declaring Foo
:
// enabling custom stuff
public protocol IntLike {
var intValue: Int { get }
}
// allowing to pass Int's
extension Int: IntLike {
public var intValue: Int { return self }
}
public class Foo {
// the placeholder
public struct FooIntLike: IntLike {
// what we really want to hide
fileprivate let realInt = 10
public init() { }
public var intValue: Int = Int.max // or 0, or whatever
}
public func doTask(amount: IntLike = FooIntLike()) {
// default value will expand to a non-nil value for `realInt`
let amount = (amount as? FooIntLike)?.realInt ?? amount.intValue
// do your stuff with the amount
}
}
Callers of doTask
are able to pass Int
's, while not knowing what the default value provides.
How about a top-level variable?
fileprivate let DefaultValue = 10
class Foo {
public func doTask(amount: Int = DefaultValue) {
...
}
}