(continuing my thoughts from my previous post)

I think a definition of `pure` that'd work well for Swift is one that is based 
on forbidding dereferencing of pointers (including object references) so that 
all you ever deal with is value semantics. With some exceptions for 
dereferencing when value semantics are preserved. Here's how it could work 
inside a pure function:

a) Structs/Locals:
Structs and local variables behave similarly. You can access `let` and `var` 
properties and mutate the later.

b) Classes:
You can't access the variables of a class in a pure function. But you can 
access its `let` properties. That's because as long as there is no `var` in the 
dereferencing path, you are guarantied to be accessing a constant. In classes, 
`let` properties are thus implicitly pure; stored `var` properties are not. 
Which means that pure instance methods on classes can only access `let` 
properties, in addition to computed properties that are themselves `pure` and 
other `pure` methods.

c) Classes (uniquely referenced):
When a class is uniquely referenced (which you can check at runtime with 
`isUniquelyReferenced`), then it's safe to access its `var` properties within a 
pure function. There is no compiler-enforced system to deal with that however, 
so you'll need a way to vouch for this. Instead of vouching, a safety mechanism 
could be built for that by statically enforcing cases where a class is known to 
be uniquely referenced.

d) Copy on Write:
COW is built on top of uniquely referenced classes. COW also needs read access 
to the storage when not uniquely referenced (so you can make a copy) which, 
again, would require vouching. Instead of vouching, a safety mechanism could be 
built to statically enforce that some instance variables (those that need to be 
copied) are only writable when the class is uniquely referenced but can 
otherwise be read at any time (perhaps by adding an attribute to those 
variables). This protects the pure function from external interference.

e) Generic Containers:
Generic containers that impose requirements on their elements will pose some 
additional problems, for instance: `Set.insert` needs to call `hashValue` and 
`==` on its elements, making the purity of `Set.insert` constrained by the 
purity of those functions. Without a way to express this kind of conditional 
purity, `Set` and `Dictionary` cannot be pure.

I feel enforcement for (c) and (d) needs to be implemented first if you are to 
implement `pure` this way so you aren't over-reliant on vouching at every 
corner. Perhaps you won't even need a vouching mechanism once that's done.


> Le 20 févr. 2017 à 11:24, Michel Fortin via swift-evolution 
> <swift-evolution@swift.org> a écrit :
> 
> Le 20 févr. 2017 à 1:19, David Sweeris <daveswee...@mac.com> a écrit :
>> 
>> On Feb 19, 2017, at 21:19, Xiaodi Wu <xiaodi...@gmail.com> wrote:
>> 
>>> This is very, very interesting. Thank you so much for the text.
>>> 
>>> If I understand your take correctly, the benefits of `pure` in Swift would 
>>> be contingent on how pervasively it can be used (as it's the composability 
>>> of pure functions that gives it exponential value). And, based on your 
>>> discussion, very few functions in Swift would be compiler-provably pure 
>>> [...]
>> 
>> I think this might, at least partly, be because we can't restrict generic 
>> parameters to be value types.
> 
> That's somewhat a problem.
> 
> But think a bit about the copy-on-write containers. Because the compiler 
> itself has no notion of copy-on-write semantics, the compiler can't prove 
> that COW types behave correctly as value types. The optimizer would have to 
> make the pessimistic assumption that dereferencing the pointer is possibly a 
> dependence on external state, making the function unoptimizable. Basically, 
> any struct with a pointer (or object reference) would need to be vouched for 
> with a "trust me" attribute, or not be vouched for if it doesn't fit value 
> semantics.
> 
> And, as you say, generic containers value-typeness will depend on their 
> generic arguments.
> 
> But... keep in mind that for the purpose of evaluating whether a function is 
> pure (as in strongly, optimizable pure), what matters really is not the type 
> but what you do with it. `Optional<AnyObject>` is not what you would call a 
> value type, but it does behave as a value type as long as you only compare it 
> to `nil`, since you never access the object.
> 
> D doesn't make this fine-grained distinction and is fine in most cases 
> because it has transitive immutability. Swift doesn't have that, so maybe we 
> should try something a bit different.
> 
> 
> -- 
> Michel Fortin
> https://michelf.ca
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

-- 
Michel Fortin
https://michelf.ca

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to