It is present and directly accessible on most keyboard layouts, which is far to be the case for £, €, ¥, or other symbol.
Other symbols largely available are #
, @
, &
, but they all have other meaning in the language.
Because you force the user to expose MyWrapper as a public member, and prevent usage of the simple projection for other use if you want to use more than one.
That would require making the property wrapper public if you want all these properties to available as public members. Furthermore if you use composition you will be forced to make all the nested property wrapper types public as well even it they are pure implementation detail types. This problem, does not exist with the design which @Chris_Lattner3 suggested.
Right... but there are other accessible symbols that are far more neutral.
Also, other symbols may be used in other contexts which may not discard them for this usage (as long as there is a clear separation). And the position could be changed to a leading position...
Some examples:
// Leading position
*variable
^variable
|variable
?variable
%variable
:variable
// Trailing position
variable@
variable%
variable*
variable^
variable|
// Leading and trailing position
|variable|
:variable:
^variable^
<variable>
%variable%
*variable*
It's my (aesthetic && neutrality)-concerned point of view...
Cheers.
It's important to note that the ascii characters that are not part of operator head are only a few and $
is one of them.
Ofc it could be check at compile time for ambiguity. We only need to look out for prefix and suffix operator, but that means it'll have some more friction than $
.
This is incorrect. It's a dollar sign (and also peso sign), not US dollar sign. It is shared among several dozens of currencies. In fact, thinking it's solely used for US is, if I may, rather egocentric.
If I may too, there is nothing incorrect in this sentence, it is indeed the money symbol of the US dollar. Had I written "solely" it would have been incorrect. And I find your answer rather aggressive and condescending.
My apologies if it appears that way, that was not my intention .
The wrapper type already has to be visible at the usage site. If you’re talking about a case where it is declared in the same module as the property it wraps, it would also need to be public in order to provide projections that are visible outside that module. How do you expect the projections to be visible when the wrapper type that provides them is not visible?
The compiler only needs to check if the projected types are public, not the property wrapper type that projects them.
Why? Imagine an internal wrapper type W
and public struct S
that are both defined in module M
. S
has a public property p
wrapped by W
. I don’t see how any projections defined by W
could be public even if the projected types are public because p
’s wrapper is not visible outside of M
.
@propertyWrapper
internal struct W {
let wrappedValue: Int
...
public var $: String { "\(wrappedValue)" }
}
public struct S {
@W
public var p: Int = 42
// translates to (I'd think that is the notation Chris Lattner wants)
private var p$storage = W(initialValue: 42)
public var p: Int { p$storage.wrappedValue }
// no need for `W` to be public, but the projection can be exposed
// by the compiler
public var p$: String { p$storage.$ }
// my translation as a grouped swift interface
public var p: Int {
get
var $: String { get }
}
}
However I would prefer _p
as the storage value here and leave the $
syntax for projected property wrapper members which can be variables and methods.
public struct S {
@W
public var p: Int = 42
private var _p = W(initialValue: 42)
// in Swift 5.1
public var p: Int {
get { _p.wrappedValue }
var $: String { _p.$ }
}
// before Swift 5.1
public var p: Int {
get { _p.wrappedValue }
}
public var p$: String { _p.$ }
}
Oh, I see what you’re saying. Since the compiler synthesizes forwarding members for all projections the wrapper type itself doesn’t need to be public.
This is possible but it would be a bit strange. Without the wrapper being visible outside the module the projections would look like hand written members with strange names. This might also have implications for documentation, etc as the documentation would be provided on the wrapper type. For these reasons I’m not sure allowing wrapper projections to be more visible than the wrapper type would be a good idea.
That's why we discuss it here. It does not mean that this is the ideal design that we'll end up with, but it's "a possibility".
That's also why I would like in this design all projections to be in the scope of property accessors. This means if the third step from Chris Lattners post would become a thing then the imported API will read like this:
public var property: Value {
get
set throws // throwing accessors of the future
var $: OtherValue { get }
var $dataBaseView: DataBaseView<Value> {
get
set
}
}
Everything would be grouped together nicely. That way the storage can remain always private
and if you ever would need to expose it, then just create a $storage
projection on the property wrapper type and return Self
.
One other huge advantage of projections like this is that they are not limited to properties but can also be methods of the property wrapper, and we may even be able to use retroactive extensions which we cannot with current wrapperValue
design.
For example:
extension MyPropertyWrapper where Value == IntWrapperWithProjection {
public var $extraProjection: Something { wrappedValue.$ }
}
// if my property was wrapped by `MyPropertyWrapper` it would automatically get a new projection:
public var property: Value {
...
var $extraProjection: Something { get }
}
My conclusion from this is that projection design through $
prefixed property wrapper instance members is a generalization of wrapperValue
which makes it more predictable, flexible and by far more powerful.
So now you are getting very close to something known as propertyBehaviour.
You can always create another type to hold these various properties/views, instead of returning self
from the wrapperValue
, and thereby avoid making the property wrapper itself public. I'm really not seeing the big benefits here, and I find property$member
unpleasant compared to $property.member
.
Like you can write Int . init()
we could say that we'd write property $ member
and treat $
as an operator to access the projected members.
It doesn't necessarily require making the property wrapper public: it could be another type that vends those properties.
So you're saying you would rather create a new type for every possible use case to circumvent the issue and add more weight to property wrapper composition?
I was thinking that as well. It's more work for the author of a wrapper that needs to vend more than one projection. But it makes the property wrapper feature much simpler overall.