You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Surge's API naming scheme does not quite follow Swift's API Design Guidelines.
We might want to fix that.
What
Swift and its stdlib have gone through several major changes since its initial release in 2014 (Surge's initial commit was shortly after, on Aug 24, 2014).
The most notable change probably was the migration to the then new and more idiomatic naming scheme with Swift 3: SE-0005, which resulted in the API Design Guidelines.
The most relevant part of them being:
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().
Those with side-effects should read as imperative verb phrases, > e.g., print(x), x.sort(), x.append(y).
Name Mutating/nonmutating method pairs consistently. A mutating > method will often have a nonmutating variant with similar semantics, > but that returns a new value rather than updating an instance > in-place.
When the operation is naturally described by a verb, use the > verb’s imperative for the mutating method and apply the “ed” or > “ing” suffix to name its nonmutating counterpart.
Mutating
Nonmutating
x.sort()
z = x.sorted()
x.append(y)
z = x.appending(y)
When the operation is naturally described by a noun, use the > noun for the nonmutating method and apply the “form” prefix to > name its mutating counterpart.
Nonmutating
Mutating
x = y.union(z)
y.formUnion(z)
j = c.successor(i)
c.formSuccessor(&i)
Why
As @mattt and I discussed in more depth in #107 the current naming scheme of our public, as well as internal API does not quite fit the idiomatic naming scheme as established with Swift 3.
Surge in its current state has the following naming scheme:
Mutating
Nonmutating
addInPlace(&a, b)
z = add(a, b)
Note: For the sake of simplicity I will refer to T: Unsafe(Mutable)MemoryAccessible as simply [Scalar] for the remainder of this writing.
Surge contains APIs for working with low-level scalar-buffers ([Scalar]), as well as APIs for working with high-level vectors (Vector<Scalar>) and matrices (Matrix<Scalar>). While both APIs are related by the fact of the latter being implemented in terms of the former, from a user's perspective they can be considered mostly unrelated, i.e. it is unlikely that an expression will contain both a [Scalar] and a Matrix<Scalar>.
A major release gives us the unique opportunity to make code-breaking changes.
How
As such I would argue that both APIs can and possibly should be dealt with individually, given their different constraints:
[Scalar]: due to dealing with generic collection types public functions can end up polluting the global namespace, adding needless noise to auto-completion, and ambiguity (e.g. Array already uses + for concatenation, forcing Surge to use .+ instead) etc.
Vector<Scalar>/Matrix<Scalar>: due to being tied to concrete and Surge-owned types there is no, or at least less, risk of namespace pollution, nor ambiguity.
As mentioned earlier, both APIs also differ in abstractness.
As such I would like to propose the following options going forward:
Option A
Keep all of Surge's API as free functions.
Change functions' naming scheme:
Nonmutating
Mutating
Idiomatic
Before:
z = add(a, b)
addInPlace(&a, b)
NO
After:
z = adding(a, b)
add(&a, b)
YES
Pro
A semi-idiomatic API for [Scalar]/Vector<Scalar>/Matrix<Scalar>.
By using @available(*, …, renamed: …) Xcode would be able to provide a reasonably effortless/automated migration path with easy fix-its.
Contra
Free functions don't quite feel at home with Swift's dominating OOP syntax.
Option B
Keep Surge's[Scalar] API as free functions, changing their naming scheme to:
Nonmutating
Mutating
Idiomatic
Before:
z = add(a, b)
addInPlace(&a, b)
NO
After:
z = adding(a, b)
add(&a, b)
YES
Turn Surge'sVector<Scalar>/Matrix<Scalar> APIs into OOP methods, changing their naming scheme to:
Nonmutating
Mutating
Idiomatic
Before:
z = add(a, b)
addInPlace(&a, b)
NO
After:
z = a.adding(b)
a.add(b)
YES
Pro
A semi-idiomatic API for [Scalar].
By using @available(*, …, renamed: …) Xcode would be able to provide a reasonably effortless/automated migration path for [Scalar] API changes with easy fix-its.
A fully idiomatic API for Vector<Scalar>/Matrix<Scalar>, following the API Design Guidelines.
Contra
[Scalar] and Vector<Scalar>/Matrix<Scalar> would have different syntax. However as mentioned earlier it is quite common to have low-level APIs use C-style free functions and high-level APIs use OOP patterns (i.e. methods). Also both APIs as unlikely to get mixed, as Vector<Scalar>/Matrix<Scalar> generally work with instances of Vector<Scalar>, not [Scalar].
It seems like @available(*, …, renamed: …) does not provide Xcode fix-its for changing an n-ary free function call into an (n-1)-ary method call on the first argument. We might want to ask the Swift Standard Library team for a recommendation here?
Deprecation vs. Removal
We would also have to decide whether we wanted to mark renamed functions as deprecated, or go straight to unavailable.
The text was updated successfully, but these errors were encountered:
tl;dr
Surge's API naming scheme does not quite follow Swift's API Design Guidelines.
We might want to fix that.
What
Swift and its stdlib have gone through several major changes since its initial release in 2014 (Surge's initial commit was shortly after, on Aug 24, 2014).
The most notable change probably was the migration to the then new and more idiomatic naming scheme with Swift 3: SE-0005, which resulted in the API Design Guidelines.
The most relevant part of them being:
Why
As @mattt and I discussed in more depth in #107 the current naming scheme of our
public
, as well asinternal
API does not quite fit the idiomatic naming scheme as established with Swift 3.Surge in its current state has the following naming scheme:
addInPlace(&a, b)
z = add(a, b)
Note: For the sake of simplicity I will refer to
T: Unsafe(Mutable)MemoryAccessible
as simply[Scalar]
for the remainder of this writing.Surge contains APIs for working with low-level scalar-buffers (
[Scalar]
), as well as APIs for working with high-level vectors (Vector<Scalar>
) and matrices (Matrix<Scalar>
). While both APIs are related by the fact of the latter being implemented in terms of the former, from a user's perspective they can be considered mostly unrelated, i.e. it is unlikely that an expression will contain both a[Scalar]
and aMatrix<Scalar>
.A major release gives us the unique opportunity to make code-breaking changes.
How
As such I would argue that both APIs can and possibly should be dealt with individually, given their different constraints:
[Scalar]
: due to dealing with generic collection typespublic
functions can end up polluting the global namespace, adding needless noise to auto-completion, and ambiguity (e.g.Array
already uses+
for concatenation, forcing Surge to use.+
instead) etc.Vector<Scalar>
/Matrix<Scalar>
: due to being tied to concrete and Surge-owned types there is no, or at least less, risk of namespace pollution, nor ambiguity.As mentioned earlier, both APIs also differ in abstractness.
As such I would like to propose the following options going forward:
Option A
z = add(a, b)
addInPlace(&a, b)
z = adding(a, b)
add(&a, b)
Pro
[Scalar]
/Vector<Scalar>
/Matrix<Scalar>
.@available(*, …, renamed: …)
Xcode would be able to provide a reasonably effortless/automated migration path with easy fix-its.Contra
Option B
[Scalar]
API as free functions, changing their naming scheme to:z = add(a, b)
addInPlace(&a, b)
z = adding(a, b)
add(&a, b)
Vector<Scalar>
/Matrix<Scalar>
APIs into OOP methods, changing their naming scheme to:z = add(a, b)
addInPlace(&a, b)
z = a.adding(b)
a.add(b)
Pro
[Scalar]
.@available(*, …, renamed: …)
Xcode would be able to provide a reasonably effortless/automated migration path for[Scalar]
API changes with easy fix-its.Vector<Scalar>
/Matrix<Scalar>
, following the API Design Guidelines.Contra
[Scalar]
andVector<Scalar>
/Matrix<Scalar>
would have different syntax. However as mentioned earlier it is quite common to have low-level APIs use C-style free functions and high-level APIs use OOP patterns (i.e. methods). Also both APIs as unlikely to get mixed, asVector<Scalar>
/Matrix<Scalar>
generally work with instances ofVector<Scalar>
, not[Scalar]
.@available(*, …, renamed: …)
does not provide Xcode fix-its for changing an n-ary free function call into an (n-1)-ary method call on the first argument. We might want to ask the Swift Standard Library team for a recommendation here?Deprecation vs. Removal
We would also have to decide whether we wanted to mark renamed functions as
deprecated
, or go straight tounavailable
.The text was updated successfully, but these errors were encountered: