I'm making a type by copying another. The original one has a single stored property that is public
and let
. Its initializer is internal
but @inlinable
. My copy has a second member, but I don't want it to be a public let
. It needs to be a var
, but I don't want anyone to modify it besides me. I tried a public private(set)
, but the compiler complained. I removed all the access levels, making it internal
, but the compiler still complained. Is it possible to have a non-public
or non-fully-public
stored property and still make the main initializer @inlinable
?
No, it is not.
I found a workaround:
public struct MyType<Base: Collection> {
@usableFromInline
internal var _newStart: Base.Index
//...
// Now this works
@inlinable
internal init(_ base: Base, i: Base.Index) {
//...
_newStart = //...
}
}
The way I use the property doesn't really need it to be made public. However adding "private(set)
" fails due to what @xwu just said. If I (or reviewers) need it to really be non-mutating public
, I could add a public computed forwarding property. I just have to hope that no one will mutate _newStart
outside my type. (Shouldn't be a problem since the type is planned for the Standard Library.)
I guess what you're after is a property with a public getter and a usableFromInline setter. I can't think you of a way to express that now.
@jrose: Can you think of any reasons we shouldn't be able to to this eventually, assuming we came up with meaningful syntax? Is this worth a bug report?
Sorry, why do we need the setter to be usableFromInline
? The initializer doesn't go through the setter unless the property has an initial value. Do we just not have that distinction in Sema?
The compiler was saying a mixed stored property ("public private(set)
" or "public internal(set)
") wasn't allowed.
With @usableFromInline public private(set) var _newStart: Base.Index
:
- The "
@usableFromInline
" line was flagged with "'@usableFromInline' attribute can only be applied to internal declarations, but '_newStart' is public
" - The assignment in the initializer was flagged with "
Setter for '_newStart' is private and cannot be referenced from an '@inlinable' function
"
With "@usableFromInline public internal(set) var _newStart: Base.Index
", the errors were the same, except the second one used "internal" instead of "private".
With "@usableFromInline internal private(set) var _newStart: Base.Index
", the first error went away, but the second (now only) one stayed.
Addendum: I want to make clear that the declaration of _newStart
does not have an initial value to it. So I guess that
may be correct.
Hm. This might be because we wouldn't want adding an initial value to change anything. …no, that's only for resilient libraries.
@Slava_Pestov, do you see any problems with allowing this? Except for the setter DI thing?
FWIW I have hundreds of public internal(set)
inlinable properties that fail to compile under Swift 5. Having this be properly supported would be very useful; the alternatives are to either expose externally-immutable variables as mutable or to separately write a computed public getter for each one.
Has there been any update on this since March? I'm also running into issues where I have multiple instances of public internal(set)
properties that are used in inalienable functions.
Was that a clever pun or a typo? Functions that cannot be removed? Functions that need to be inlinable? Or both?
Haha good catch! Apparently autocorrect on the Mac corrects "inlinable" to "inalienable". :)