100% bikeshed topic: DictionaryLiteral

I specifically want "Array" in the name, because this type has the same semantics as an array:

* RandomAccessCollection
* Contiguous, zero-based Int indices
* Isn't currently, but could be, MutableCollection and RangeReplaceableCollection

···

On Jan 13, 2018, at 1:40 PM, Erica Sadun <erica@ericasadun.com> wrote:

On Jan 9, 2018, at 10:22 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:
If we can't do this, I think we should call it something like `PairArray` or `KeyValueArray`

Or "KeyValueList", which avoids both "Dictionary" and "Array" words.

--
Brent Royal-Gordon
Architechies

Because at the point of use, “DictionaryLiteral” is instantiated with an
actual dictionary literal, eg. “[a: 1, b: 2, c: 3]”, and that syntax isn’t
available for an array of key-value pairs. As near as I can tell, the
convenience of that spelling is the entire *raison-d’être* for
“DictionaryLiteral” in the first place.

The ulterior question of whether preserving “DictionaryLiteral” is
worthwhile, is apparently out of scope. Personally, I have a hard time
imagining a compelling use-case outside of the standard library, and I
doubt it’s being used “in the wild” (I checked several projects in the
source-compatibility suite and found zero occurrences).

Nevin

···

On Mon, Jan 8, 2018 at 11:53 PM, Xiaodi Wu via swift-evolution < swift-evolution@swift.org> wrote:

Thank you for the clarification. It occurred to me in the shower that this
might be the case, and that I was entirely mistaken as to what we were
talking about.

Yes, then, I wholeheartedly agree on this point. Out of curiosity, why are
there source stability issues to 'typealias DictionaryLiteral<Key, Value> =
[(Key, Value)]'?

Thank you for the clarification. It occurred to me in the shower that
this might be the case, and that I was entirely mistaken as to what we were
talking about.

Yes, then, I wholeheartedly agree on this point. Out of curiosity, why
are there source stability issues to 'typealias DictionaryLiteral<Key,
> = [(Key, Value)]'?

Because at the point of use, “DictionaryLiteral” is instantiated with an
actual dictionary literal, eg. “[a: 1, b: 2, c: 3]”, and that syntax isn’t
available for an array of key-value pairs.

Why do we need available syntax? Sure, conformance of [(Key, Value)] to
ExpressibleByDictionaryLiteral can't be written in Swift, but we could make
this a built-in conformance. Literals are magical in many ways no matter
what.

As near as I can tell, the convenience of that spelling is the entire

*raison-d’être* for “DictionaryLiteral” in the first place.

The ulterior question of whether preserving “DictionaryLiteral” is
worthwhile, is apparently out of scope. Personally, I have a hard time
imagining a compelling use-case outside of the standard library, and I
doubt it’s being used “in the wild” (I checked several projects in the
source-compatibility suite and found zero occurrences).

I have seen examples where its use is encouraged, and I see no reason to
address this "ulterior question."

···

On Tue, Jan 9, 2018 at 00:40 Nevin Brackett-Rozinsky < nevin.brackettrozinsky@gmail.com> wrote:

On Mon, Jan 8, 2018 at 11:53 PM, Xiaodi Wu via swift-evolution < > swift-evolution@swift.org> wrote:

DictionaryLiteral is worthwhile. The SQLite library GRDB uses DictionaryLiteral in order to build database rows (which may have duplicated column names, and whose column ordering is important). This is mostly useful for tests:

    let row = try Row.fetchOne(db, "SELECT 1 AS a, 2 AS a")!
    XCTAssertEqual(row, ["a": 1, "a": 2])

Gwendal

···

Le 9 janv. 2018 à 06:40, Nevin Brackett-Rozinsky via swift-evolution <swift-evolution@swift.org> a écrit :

The ulterior question of whether preserving “DictionaryLiteral” is worthwhile, is apparently out of scope. Personally, I have a hard time imagining a compelling use-case outside of the standard library, and I doubt it’s being used “in the wild” (I checked several projects in the source-compatibility suite and found zero occurrences).

2 Likes

I used a DictionaryLiteral only yesterday, and it turned what would have a typically unreadable array of Structs into something much more elegant. I'm pretty sure the only reason Literals (of all varieties) aren't used more often is because Swift programmers don't realize they are available and easy to implement.

···

Sent from my telephone

On Jan 8, 2018, at 9:40 PM, Nevin Brackett-Rozinsky via swift-evolution <swift-evolution@swift.org> wrote:

On Mon, Jan 8, 2018 at 11:53 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:
Thank you for the clarification. It occurred to me in the shower that this might be the case, and that I was entirely mistaken as to what we were talking about.

Yes, then, I wholeheartedly agree on this point. Out of curiosity, why are there source stability issues to 'typealias DictionaryLiteral<Key, Value> = [(Key, Value)]'?

Because at the point of use, “DictionaryLiteral” is instantiated with an actual dictionary literal, eg. “[a: 1, b: 2, c: 3]”, and that syntax isn’t available for an array of key-value pairs. As near as I can tell, the convenience of that spelling is the entire raison-d’être for “DictionaryLiteral” in the first place.

The ulterior question of whether preserving “DictionaryLiteral” is worthwhile, is apparently out of scope. Personally, I have a hard time imagining a compelling use-case outside of the standard library, and I doubt it’s being used “in the wild” (I checked several projects in the source-compatibility suite and found zero occurrences).

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

Disclaimer: I’m reordering your comments below to suit my nefarious purposes: :slight_smile:

More to the point though, this seems like an implementation detail of Mirrors. What is the plan for Mirrors + ABI stability?

Absent a proposal to change them to something better (and I’m not aware of one pending), the plan is they are what they are, at least the public API of Swift.Mirror. I would guess this whole area is a candidate to be overhauled significantly at some point in the post-Swift 5 future with some more fully-fledged reflection system, but there is little chance of this happening before ABI stability, and interim tinkering doesn’t seem worthwhile to me.

Ok, I understand that (among all the other things going on that are clearly more important) revamping this is probably not the highest priority thing to do. That said, it would be really unfortunate to carry around these “suboptimal” APIs forever, particularly given how marginal they are (as in, not widely used). I’m sure that there are other examples beyond these that are similarly unfortunate.

Given that, I have a meta question for you: have you considered an approach where you take the Swift standard library and split it into two conceptual pieces:

1) The "ABI stable” subset of the library that gets burned into the OS.
2) The “ABI unstable” subset, which gets statically linked into apps, just like the Swift 4 library used to?

Given that “import Swift” is implicit anyway, you could just have the compiler implicitly import *both* of these modules.

The point of doing this is that it gives you a very general and low friction way to handle compatibility gunk. In addition to putting obscure stuff like Mirror and “DictionaryLiteral” into this (without breaking source code!) you now get the ability to put the various deprecated forwarding functions in this module as well, avoiding them becoming part of the ABI.

The nice thing about this is that only people who use these things would have to pay the cost, and you can directly message this by deprecating all the stuff in it. Think about it as an overlay for the Swift standard library :slight_smile:

+1 for renaming it to something that isn’t super confusing, but +100 for removing it outright.

Rationale: if we didn’t have this functionality in the stdlib today, we would not consider adding it. It doesn’t meet the bar we’ve set for what is in the standard library. It only exists there by historical accident. The Mirror API was not carefully considered.

Personally, I feel like this argument for removal as past its use-by date. It was a good reason for Swift 3, tenuous for 4 and should be ruled out for 5, since the source stability bar has been raised since. Like I said, IMO the criteria should now be “active harm”. I also don’t think searches of GitHub etc are sufficient justification, except when combined with the active-harm argument. I also don’t think the origin story of the type – whether accidental or intentional – is relevant to the decision of what to do with it now. It exists and people can legitimately use it for their own purposes independent of mirrors.

I’m generally in agreement with you, but in this specific case, I seriously doubt people are using this. All rules are malleable in the right circumstances.

More importantly though, if we had a meta design that allowed to gracefully phase this sort of thing out (without it becoming part of ABI under any name) there becomes very little cost to leaving it around in the “abi unstable” library for…. ever if need be. Given that, I would have much less objection to keeping it around.

-Chris

···

On Jan 9, 2018, at 3:48 PM, Ben Cohen <ben_cohen@apple.com> wrote:

No, that is not what I’m talking about at all. Mirrors are completely wrong. There is nothing saving them, they must be replaced. It is now clear that isn’t going to happen this year (which is fine) but that doesn’t mean that they should be a first class part of the Swift experience “forever”.

We have an opportunity here to fix this.

-Chris

···

On Jan 11, 2018, at 12:22 AM, Ted Kremenek <kremenek@apple.com> wrote:

On Jan 9, 2018, at 11:48 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

IMO that isn’t a question we should be asking any more except in cases where an existing implementation is causing active harm. Which, confusing name aside, this type isn’t (aside from API sprawl I guess).

It directly impacts code size for applications of swift that use the standard library as a standard library, e.g. a raspberry pi dev situation.

I’m not arguing that we should have profligate bloat in the Standard library, but I feel that if we are seriously talking about scenarios where we want a super-svelt Standard library for particular use-cases where code size and other factors are a major concern,

The ulterior question of whether preserving “DictionaryLiteral” is worthwhile, is apparently out of scope. Personally, I have a hard time imagining a compelling use-case outside of the standard library, and I doubt it’s being used “in the wild” (I checked several projects in the source-compatibility suite and found zero occurrences).

DictionaryLiteral is worthwhile. The SQLite library GRDB uses DictionaryLiteral in order to build database rows (which may have duplicated column names, and whose column ordering is important). This is mostly useful for tests:

    let row = try Row.fetchOne(db, "SELECT 1 AS a, 2 AS a")!
    XCTAssertEqual(row, ["a": 1, "a": 2])

Gwendal

Chris Lattner's wrote:

why is maintaining duplicate keys a feature?

Since it is immutable, why not sort the keys in the initializer, allowing an efficient binary search to look up values?

I really wish both duplicated keys and key ordering would be preserved, since both are needed for the above sample code.

Should those features be lost, the sky wouldn't fall, that's sure. But we'd have to write something much less easy to wrote and read:

  XCTAssertEqual(row.map { $0 }, [("a", 1), ("a", 2)])

Gwendal

···

Le 9 janv. 2018 à 08:06, Gwendal Roué via swift-evolution <swift-evolution@swift.org> a écrit :

Le 9 janv. 2018 à 06:40, Nevin Brackett-Rozinsky via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

Could you provide an example of how you used DictionaryLiteral?

Nevin

···

On Tue, Jan 9, 2018 at 7:47 PM, charles@charlesism.com < charlesism.com@gmail.com> wrote:

I used a DictionaryLiteral only yesterday, and it turned what would have a
typically unreadable array of Structs into something much more elegant. I'm
pretty sure the only reason Literals (of all varieties) aren't used more
often is because Swift programmers don't realize they are available and
easy to implement.

It's true that they are not widely used, but they are in use. For
example IBM's SQL abstraction library called "Kuery" depends on
Mirror.

https://github.com/IBM-Swift/Swift-Kuery/blob/1d05ad6435cf7fa5feebba663bd3f765c72634e1/Sources/SwiftKuery/Table.swift#L42

···

On 10 January 2018 at 06:29, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

Ok, I understand that (among all the other things going on that are clearly more important) revamping
this is probably not the highest priority thing to do. That said, it would be really unfortunate to carry
around these “suboptimal” APIs forever, particularly given how marginal they are (as in, not widely used).

--
Ian Partridge

Excellent Idea!

I am all for this. It shouldn’t be too complicated to add a second implicit import and only code that is actually using this stuff will have increased code size.

···

On Jan 9, 2018, at 10:29 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

Disclaimer: I’m reordering your comments below to suit my nefarious purposes: :slight_smile:

On Jan 9, 2018, at 3:48 PM, Ben Cohen <ben_cohen@apple.com> wrote:

More to the point though, this seems like an implementation detail of Mirrors. What is the plan for Mirrors + ABI stability?

Absent a proposal to change them to something better (and I’m not aware of one pending), the plan is they are what they are, at least the public API of Swift.Mirror. I would guess this whole area is a candidate to be overhauled significantly at some point in the post-Swift 5 future with some more fully-fledged reflection system, but there is little chance of this happening before ABI stability, and interim tinkering doesn’t seem worthwhile to me.

Ok, I understand that (among all the other things going on that are clearly more important) revamping this is probably not the highest priority thing to do. That said, it would be really unfortunate to carry around these “suboptimal” APIs forever, particularly given how marginal they are (as in, not widely used). I’m sure that there are other examples beyond these that are similarly unfortunate.

Given that, I have a meta question for you: have you considered an approach where you take the Swift standard library and split it into two conceptual pieces:

1) The "ABI stable” subset of the library that gets burned into the OS.
2) The “ABI unstable” subset, which gets statically linked into apps, just like the Swift 4 library used to?

Given that “import Swift” is implicit anyway, you could just have the compiler implicitly import *both* of these modules.

The point of doing this is that it gives you a very general and low friction way to handle compatibility gunk. In addition to putting obscure stuff like Mirror and “DictionaryLiteral” into this (without breaking source code!) you now get the ability to put the various deprecated forwarding functions in this module as well, avoiding them becoming part of the ABI.

The nice thing about this is that only people who use these things would have to pay the cost, and you can directly message this by deprecating all the stuff in it. Think about it as an overlay for the Swift standard library :slight_smile:

+1 for renaming it to something that isn’t super confusing, but +100 for removing it outright.

Rationale: if we didn’t have this functionality in the stdlib today, we would not consider adding it. It doesn’t meet the bar we’ve set for what is in the standard library. It only exists there by historical accident. The Mirror API was not carefully considered.

Personally, I feel like this argument for removal as past its use-by date. It was a good reason for Swift 3, tenuous for 4 and should be ruled out for 5, since the source stability bar has been raised since. Like I said, IMO the criteria should now be “active harm”. I also don’t think searches of GitHub etc are sufficient justification, except when combined with the active-harm argument. I also don’t think the origin story of the type – whether accidental or intentional – is relevant to the decision of what to do with it now. It exists and people can legitimately use it for their own purposes independent of mirrors.

I’m generally in agreement with you, but in this specific case, I seriously doubt people are using this. All rules are malleable in the right circumstances.

More importantly though, if we had a meta design that allowed to gracefully phase this sort of thing out (without it becoming part of ABI under any name) there becomes very little cost to leaving it around in the “abi unstable” library for…. ever if need be. Given that, I would have much less objection to keeping it around.

-Chris

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

Hi Chris,

Even if we split the APIs into two sets, with an “ABI unstable” subset, we are still going to “carry round these ’suboptimal APIs’” because clients are using them today and those APIs — without an active plan to remove them — *are* a part of the Standard Library. We’ve past the point in Swift where we can just rip them out (you said so yourself in a follow up email).

It feels to me that the main advantage of the overlay is a solution to remove out pieces of the Standard Library that will be used in practice less, and thus clients don’t “pay the cost” when they don’t use them. But I think we should be honest about what that “cost” actually is, as these APIs aren’t going away right now. These suboptimal APIs will stay around at least until better ones are created, and even then some existing clients will want to rely on the existing suboptimal APIs anyway even if others want to take advantage of newer, better APIs and idioms.

The main cost I see here that we save by having an “overlay for the Standard library" is code size. On macOS/iOS it is true that applications embed a copy of the Standard Library within them and thus pay a real cost in the Standard Library’s actually payload size in their own app. However, the only reason that is necessary today is because we don’t have ABI stability. With ABI stability, other options for shipping the Standard Library — such as shipping it in the OS — become possible, and thus the burden of shouldering that “cost” of code size shifts around. Then the tradeoffs of having an overlay for the Standard Library are different. In a world with ABI stability, is it better to have a Standard Library "overlay" that only some clients use, and embed within their application bundle, than just eat that cost in the Standard Library to be shared by potentially multiple clients installed on a system? I think it really comes down to the numbers. In that case, are we really just talking about Mirrors? I haven’t run the numbers here, but my intuition tells me we are talking about a relatively small code size impact overall.

There’s also other potential performance implications from doing this split. Being able to have the Standard Library be in the OS has potential major implications on the startup time of Swift applications. Right now, with the Swift overlay libraries being part of the application bundle, on macOS/iOS there is a real startup time impact of having these libraries shipped in applications this way. Obviously reducing these down to one overlay — and overlay that hypothetically wouldn’t be used often — would be a major improvement over what we have today. But this would also introduce a performance cliff for some clients that wanted to use the parts of the Standard Library that were deemed “ABI unstable”. If an app starts using one of the APIs in this part of the Standard Library — and possibly through an intermediary such as a Swift package — then the app silently starts using this overlay and thus gets the startup time hit and other costs of using it. For some clients that will seem like an obscure performance cliff. In all fairness, “cliff” might be hyperbole here, but my point is that the tradeoffs of costs here are not linear and make the performance programming model of using Swift a little more complicated.

Can you elaborate a bit more on the specific “cost” factors you are using when proposing to have a Standard Library overlay? I think that’s really important to help calibrate the dialogue here. I suspect different participants on this thread have different optics on what ABI stability allows and disallows, and I suspect your concerns are about paying specific costs into terms of carrying forward what could be perceived as historical baggage, and less about being able to make changes in the future. Is that a correct interpretation?

Ted

···

On Jan 9, 2018, at 10:29 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

Ok, I understand that (among all the other things going on that are clearly more important) revamping this is probably not the highest priority thing to do. That said, it would be really unfortunate to carry around these “suboptimal” APIs forever, particularly given how marginal they are (as in, not widely used). I’m sure that there are other examples beyond these that are similarly unfortunate.

Given that, I have a meta question for you: have you considered an approach where you take the Swift standard library and split it into two conceptual pieces:

1) The "ABI stable” subset of the library that gets burned into the OS.
2) The “ABI unstable” subset, which gets statically linked into apps, just like the Swift 4 library used to?

Given that “import Swift” is implicit anyway, you could just have the compiler implicitly import *both* of these modules.

The point of doing this is that it gives you a very general and low friction way to handle compatibility gunk. In addition to putting obscure stuff like Mirror and “DictionaryLiteral” into this (without breaking source code!) you now get the ability to put the various deprecated forwarding functions in this module as well, avoiding them becoming part of the ABI.

The nice thing about this is that only people who use these things would have to pay the cost, and you can directly message this by deprecating all the stuff in it. Think about it as an overlay for the Swift standard library :slight_smile:

I'm not sure a valid use case by a third party makes it hold its weight
for inclusion in the stdlib. Reproducing its feature set is extremely
trivial, and would probably allow you to hint the implementation details
better for your use case.
Zach
zach@waldowski.me

···

On Tue, Jan 9, 2018, at 2:12 AM, Gwendal Roué via swift-evolution wrote:>

Le 9 janv. 2018 à 08:06, Gwendal Roué via swift-evolution <swift- >> evolution@swift.org> a écrit :>>

Le 9 janv. 2018 à 06:40, Nevin Brackett-Rozinsky via swift-evolution >>> <swift-evolution@swift.org> a écrit :>>>
The ulterior question of whether preserving “DictionaryLiteral” is
worthwhile, is apparently out of scope. Personally, I have a hard
time imagining a compelling use-case outside of the standard
library, and I doubt it’s being used “in the wild” (I checked
several projects in the source-compatibility suite and found zero
occurrences).>>

DictionaryLiteral is worthwhile. The SQLite library GRDB uses
DictionaryLiteral in order to build database rows (which may have
duplicated column names, and whose column ordering is important).
This is mostly useful for tests:>>
    let row = try Row.fetchOne(db, "SELECT 1 AS a, 2 AS a")!
    XCTAssertEqual(row, ["a": 1, "a": 2])

Gwendal

Chris Lattner's wrote:

why is maintaining duplicate keys a feature?
Since it is immutable, why not sort the keys in the initializer,
allowing an efficient binary search to look up values?>

I really wish both duplicated keys and key ordering would be
preserved, since both are needed for the above sample code.>
Should those features be lost, the sky wouldn't fall, that's sure. But
we'd have to write something much less easy to wrote and read:>
XCTAssertEqual(row.map { $0 }, [("a", 1), ("a", 2)])

Gwendal

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

Hi Nevin (et al)

Here's the relevant section of my code. It's from a protocol I use called
"ParameterSet" to extend OptionSets to contain small numbers (like an Enum
with an associated type, but all the data is stored in the UInt). Wouldn't
be my first choice to share, as it breaks KISS. Anyhow, the
"ExpressibleByDictionaryLiteral" lets me specify a "params" template
tersely. I only found out how to use the -Literal initializers last year. I
love them.

struct DrumNote: ParameterSet {
let rawValue: UInt

static let params: [ParamType] = [ ["velocity":0...255], "flam", "roll",
"reverse" ]

static let
velocity = param(0),
flam = param(1),
roll = param(2),
reverse = param(3),

// ...

}

enum ParamType: ExpressibleByStringLiteral, ExpressibleByDictionaryLiteral {
public init( dictionaryLiteral elements: (String,Any)... ) {
if let pair = elements.first as? (String,ClosedRange<FloatLiteralType>) {
self = .doub(pair.0,pair.1) }
else if let pair = elements.first as?
(String,CountableClosedRange<IntegerLiteralType>) { self = .int(pair.0,
pair.1.lowerBound ... pair.1.upperBound ) }
else { fatalError("Can only init from Double...Double or Int...Int") }
}

// ...
}

···

On Tue, Jan 9, 2018 at 6:10 PM, Nevin Brackett-Rozinsky < nevin.brackettrozinsky@gmail.com> wrote:

On Tue, Jan 9, 2018 at 7:47 PM, charles@charlesism.com < > charlesism.com@gmail.com> wrote:

I used a DictionaryLiteral only yesterday, and it turned what would have
a typically unreadable array of Structs into something much more elegant.
I'm pretty sure the only reason Literals (of all varieties) aren't used
more often is because Swift programmers don't realize they are available
and easy to implement.

Could you provide an example of how you used DictionaryLiteral?

Nevin

Oops. Kindly disregard my previous emails. Ben was kind enough to point out
to me that I was confusing dictionary literals with DictionaryLiteral

···

On Tue, Jan 9, 2018 at 8:56 PM, Ben Cohen <> wrote:

Hi Charles,

The naming issue strikes again :slight_smile:

Your code is making use of dictionary literals, not DictionaryLiteral. We
are talking about the (clearly confusingly named!) DictionaryLiteral type,
which is a type you can create from a dictionary literal. (See docs here:
https://developer.apple.com/documentation/swift/dictionaryliteral)

There’s no suggestion of getting rid of the ExpressibleByDictionaryLiteral
capability.

“Ceci n’est pas une literal”
- Magritte

On Jan 9, 2018, at 8:26 PM, Charles Constant via swift-evolution < > swift-evolution@swift.org> wrote:

Hi Nevin (et al)

Here's the relevant section of my code. It's from a protocol I use called
"ParameterSet" to extend OptionSets to contain small numbers (like an Enum
with an associated type, but all the data is stored in the UInt). Wouldn't
be my first choice to share, as it breaks KISS. Anyhow, the "
ExpressibleByDictionaryLiteral" lets me specify a "params" template
tersely. I only found out how to use the -Literal initializers last year. I
love them.

struct DrumNote: ParameterSet {
let rawValue: UInt

static let params: [ParamType] = [ ["velocity":0...255], "flam", "roll",
"reverse" ]

static let
velocity = param(0),
flam = param(1),
roll = param(2),
reverse = param(3),

// ...

}

enum ParamType: ExpressibleByStringLiteral, ExpressibleByDictionaryLiteral
{
public init( dictionaryLiteral elements: (String,Any)... ) {
if let pair = elements.first as? (String,ClosedRange<FloatLiteralType>) {
self = .doub(pair.0,pair.1) }
else if let pair = elements.first as? (String,CountableClosedRange<IntegerLiteralType>)
{ self = .int(pair.0, pair.1.lowerBound ... pair.1.upperBound ) }
else { fatalError("Can only init from Double...Double or Int...Int") }
}

// ...
}

On Tue, Jan 9, 2018 at 6:10 PM, Nevin Brackett-Rozinsky < > nevin.brackettrozinsky@gmail.com> wrote:

On Tue, Jan 9, 2018 at 7:47 PM, charles@charlesism.com < >> charlesism.com@gmail.com> wrote:

I used a DictionaryLiteral only yesterday, and it turned what would have
a typically unreadable array of Structs into something much more elegant.
I'm pretty sure the only reason Literals (of all varieties) aren't used
more often is because Swift programmers don't realize they are available
and easy to implement.

Could you provide an example of how you used DictionaryLiteral?

Nevin

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

On Tue, Jan 9, 2018 at 8:26 PM, Charles Constant via swift-evolution < swift-evolution@swift.org> wrote:

Hi Nevin (et al)

Here's the relevant section of my code. It's from a protocol I use called
"ParameterSet" to extend OptionSets to contain small numbers (like an Enum
with an associated type, but all the data is stored in the UInt). Wouldn't
be my first choice to share, as it breaks KISS. Anyhow, the "
ExpressibleByDictionaryLiteral" lets me specify a "params" template
tersely. I only found out how to use the -Literal initializers last year. I
love them.

struct DrumNote: ParameterSet {
let rawValue: UInt

static let params: [ParamType] = [ ["velocity":0...255], "flam", "roll",
"reverse" ]

static let
velocity = param(0),
flam = param(1),
roll = param(2),
reverse = param(3),

// ...

}

enum ParamType: ExpressibleByStringLiteral, ExpressibleByDictionaryLiteral
{
public init( dictionaryLiteral elements: (String,Any)... ) {
if let pair = elements.first as? (String,ClosedRange<FloatLiteralType>) {
self = .doub(pair.0,pair.1) }
else if let pair = elements.first as? (String,CountableClosedRange<IntegerLiteralType>)
{ self = .int(pair.0, pair.1.lowerBound ... pair.1.upperBound ) }
else { fatalError("Can only init from Double...Double or Int...Int") }
}

// ...
}

On Tue, Jan 9, 2018 at 6:10 PM, Nevin Brackett-Rozinsky < > nevin.brackettrozinsky@gmail.com> wrote:

On Tue, Jan 9, 2018 at 7:47 PM, charles@charlesism.com < >> charlesism.com@gmail.com> wrote:

I used a DictionaryLiteral only yesterday, and it turned what would have
a typically unreadable array of Structs into something much more elegant.
I'm pretty sure the only reason Literals (of all varieties) aren't used
more often is because Swift programmers don't realize they are available
and easy to implement.

Could you provide an example of how you used DictionaryLiteral?

Nevin

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

Right. That’s exactly the reason we don’t want to remove them outright (that would be a major source breakage). Moving them to a separate module solves this concern and allows a better implementation to come in and be standardized later.

-Chris

···

On Jan 10, 2018, at 1:52 AM, Ian Partridge <ian@poncho.org.uk> wrote:

On 10 January 2018 at 06:29, Chris Lattner via swift-evolution > <swift-evolution@swift.org> wrote:

Ok, I understand that (among all the other things going on that are clearly more important) revamping
this is probably not the highest priority thing to do. That said, it would be really unfortunate to carry
around these “suboptimal” APIs forever, particularly given how marginal they are (as in, not widely used).

It's true that they are not widely used, but they are in use. For
example IBM's SQL abstraction library called "Kuery" depends on
Mirror.

https://github.com/IBM-Swift/Swift-Kuery/blob/1d05ad6435cf7fa5feebba663bd3f765c72634e1/Sources/SwiftKuery/Table.swift#L42

If I understand this correctly. This is exactly the same argument in favor
to maintain the ABI unstable and always bundle the standard library and the
runtime with the app.

Another alternative is, not only, separate the standard library on small
pieces, but also dynamic link this specific version of this piece and keep
all versions on the SO. (I think the Microsoft did something similar to
this)

On Linux the package manager probably will handle this very well like any
other library.

Even 100 versions in the same SO will not consume enough space to bother
anyone.

···

Em qua, 10 de jan de 2018 às 17:04, Hooman Mehr via swift-evolution < swift-evolution@swift.org> escreveu:

Excellent Idea!

I am all for this. It shouldn’t be too complicated to add a second
implicit import and only code that is actually using this stuff will have
increased code size.

> On Jan 9, 2018, at 10:29 PM, Chris Lattner via swift-evolution < > swift-evolution@swift.org> wrote:
>
> Disclaimer: I’m reordering your comments below to suit my nefarious
purposes: :slight_smile:
>
> On Jan 9, 2018, at 3:48 PM, Ben Cohen <ben_cohen@apple.com> wrote:
>>> More to the point though, this seems like an implementation detail of
Mirrors. What is the plan for Mirrors + ABI stability?
>>>
>>
>> Absent a proposal to change them to something better (and I’m not aware
of one pending), the plan is they are what they are, at least the public
API of Swift.Mirror. I would guess this whole area is a candidate to be
overhauled significantly at some point in the post-Swift 5 future with some
more fully-fledged reflection system, but there is little chance of this
happening before ABI stability, and interim tinkering doesn’t seem
worthwhile to me.
>
> Ok, I understand that (among all the other things going on that are
clearly more important) revamping this is probably not the highest priority
thing to do. That said, it would be really unfortunate to carry around
these “suboptimal” APIs forever, particularly given how marginal they are
(as in, not widely used). I’m sure that there are other examples beyond
these that are similarly unfortunate.
>
> Given that, I have a meta question for you: have you considered an
approach where you take the Swift standard library and split it into two
conceptual pieces:
>
> 1) The "ABI stable” subset of the library that gets burned into the OS.
> 2) The “ABI unstable” subset, which gets statically linked into apps,
just like the Swift 4 library used to?
>
> Given that “import Swift” is implicit anyway, you could just have the
compiler implicitly import *both* of these modules.
>
>
> The point of doing this is that it gives you a very general and low
friction way to handle compatibility gunk. In addition to putting obscure
stuff like Mirror and “DictionaryLiteral” into this (without breaking
source code!) you now get the ability to put the various deprecated
forwarding functions in this module as well, avoiding them becoming part of
the ABI.
>
> The nice thing about this is that only people who use these things would
have to pay the cost, and you can directly message this by deprecating all
the stuff in it. Think about it as an overlay for the Swift standard
library :slight_smile:
>
>>> +1 for renaming it to something that isn’t super confusing, but +100
for removing it outright.
>>>
>>> Rationale: if we didn’t have this functionality in the stdlib today,
we would not consider adding it. It doesn’t meet the bar we’ve set for
what is in the standard library. It only exists there by historical
accident. The Mirror API was not carefully considered.
>>>
>>
>> Personally, I feel like this argument for removal as past its use-by
date. It was a good reason for Swift 3, tenuous for 4 and should be ruled
out for 5, since the source stability bar has been raised since. Like I
said, IMO the criteria should now be “active harm”. I also don’t think
searches of GitHub etc are sufficient justification, except when combined
with the active-harm argument. I also don’t think the origin story of the
type – whether accidental or intentional – is relevant to the decision of
what to do with it now. It exists and people can legitimately use it for
their own purposes independent of mirrors.
>
> I’m generally in agreement with you, but in this specific case, I
seriously doubt people are using this. All rules are malleable in the
right circumstances.
>
> More importantly though, if we had a meta design that allowed to
gracefully phase this sort of thing out (without it becoming part of ABI
under any name) there becomes very little cost to leaving it around in the
“abi unstable” library for…. ever if need be. Given that, I would have
much less objection to keeping it around.
>
> -Chris
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

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

The nice thing about this is that only people who use these things would have to pay the cost, and you can directly message this by deprecating all the stuff in it. Think about it as an overlay for the Swift standard library :slight_smile:

Hi Chris,

Even if we split the APIs into two sets, with an “ABI unstable” subset, we are still going to “carry round these ’suboptimal APIs’” because clients are using them today and those APIs — without an active plan to remove them — *are* a part of the Standard Library. We’ve past the point in Swift where we can just rip them out (you said so yourself in a follow up email).

Who is “we” and how do you define carry?

I think you’re saying that they will remain part of the swift project (in the “SwiftDeprecated” module) for effectively ever. If so, I agree, and that’s the point. The point is that the code can continue to exist and service the few people who need it (and will become even fewer over the years) without causing *harm* to the Swift ecosystem over the near or long term. That’s the feature.

It feels to me that the main advantage of the overlay is a solution to remove out pieces of the Standard Library that will be used in practice less, and thus clients don’t “pay the cost” when they don’t use them.

Yes, exactly.

But I think we should be honest about what that “cost” actually is, as these APIs aren’t going away right now. These suboptimal APIs will stay around at least until better ones are created, and even then some existing clients will want to rely on the existing suboptimal APIs anyway even if others want to take advantage of newer, better APIs and idioms.

I’m not sure what you mean. I’m talking about two things specifically:

1) APIs that are already deprecated and have replacements. The deprecated version goes in this library, avoid carrying them around forever.

2) APIs that are used by extremely narrow audiences, which were added without much consideration and that have not been redesigned since Swift 1. Mirror’s are an example of this. I’m arguing that these should be moved to this SwiftDeprecated module - but not actually deprecated until a replacement exists.

I don’t see how this is bad for anyone, and I think this provides a significant process improvement compared to your current approach, which forces you to lock down APIs now without careful consideration just because they are not “important enough”.

The main cost I see here that we save by having an “overlay for the Standard library" is code size.

I don’t understand this point.

On macOS/iOS it is true that applications embed a copy of the Standard Library within them and thus pay a real cost in the Standard Library’s actually payload size in their own app. However, the only reason that is necessary today is because we don’t have ABI stability. With ABI stability, other options for shipping the Standard Library — such as shipping it in the OS — become possible, and thus the burden of shouldering that “cost” of code size shifts around. Then the tradeoffs of having an overlay for the Standard Library are different. In a world with ABI stability, is it better to have a Standard Library "overlay" that only some clients use, and embed within their application bundle, than just eat that cost in the Standard Library to be shared by potentially multiple clients installed on a system? I think it really comes down to the numbers. In that case, are we really just talking about Mirrors? I haven’t run the numbers here, but my intuition tells me we are talking about a relatively small code size impact overall.

This comment doesn’t make a lot of sense to me, perhaps we’re talking across each other. The point of the design that I’m advocating for is that all apps (that deploy to iOS-next or later) get a immediate improvement from abi stability: the vast majority of the standard library is not put into their app bundle. Further, the vastly most common apps - those that are not using mirrors or deprecated APIs, also do not include the SwiftDeprecated module.

Only the tiny minority of apps that do use these APIs would have a copy of SwiftDeprecated in their app dylib, but they have a path to fix that, and they would still see a huge improvement from the bulk of the standard library being out of their app bundle.

There’s also other potential performance implications from doing this split.

This doesn’t make sense to me. We’re not talking about taking comonly used apis here. Mirrors are not performance sensitive at all, and neither are deprecated wrappers of renamed APIs.

Being able to have the Standard Library be in the OS has potential major implications on the startup time of Swift applications.

It is great for app developers to have an incentive to stop using deprecated APIs! :slight_smile:

Can you elaborate a bit more on the specific “cost” factors you are using when proposing to have a Standard Library overlay?

I think it is possible that you’re reading too much into the “overlay" word here, so ignore that. The design I’m proposing is really simple:

1. The vast majority of the standard library goes into the OS. This includes all the string, array, and other stuff people use.
2. The deprecated wrappers and obscure APIs go into a new module, and that module doesn’t go into the OS. Only people that use it pay to cost.

This isn’t particularly complicated, if give you new ways to manage the process of stdlib ABI stability, and I don’t see the downside.

-Chris

···

On Jan 11, 2018, at 12:01 AM, Ted Kremenek <kremenek@apple.com> wrote:

Right. The functionality can be moved out to a third party package outside the stdlib, or copied directly into a project that needs it (worse case). We’re not removing the ability for Swift code to do this, just talking about removing it from the swift standard library (which has a very high bar for functionality).

-Chris

···

On Jan 9, 2018, at 8:16 AM, Zach Waldowski via swift-evolution <swift-evolution@swift.org> wrote:

I'm not sure a valid use case by a third party makes it hold its weight for inclusion in the stdlib. Reproducing its feature set is extremely trivial, and would probably allow you to hint the implementation details better for your use case.

I'm not sure a valid use case by a third party makes it hold its weight for inclusion in the stdlib.

You're definitely right, and that's why I wrote with the most humble tone I could.

Yet, the design of the stdlib *requires* some speculation about use cases, and speculation is *helped* by the exposition of actual uses. I'm not sure readers of the mailing list had any idea of the use cases of the current DictionaryLiteral, and maybe I helped a little.

Reproducing its feature set is extremely trivial, and would probably allow you to hint the implementation details better for your use case.

Please define "trivial".

In case anybody would wonder, in the line below the `row` variable is of type Row which happens to adopt ExpressibleByDictionaryLiteral. It is not of type DictionaryLiteral. The use case here is the ability to express a row with a dictionary literal that accepts duplicated keys and preserves ordering:

  XCTAssertEqual(row, ["a": 1, "a": 2])

I don't see how anything could better fit this use case than the current DictionaryLiteral. This is not *my* use case, but the use case of anyone that wants to model database rows beyond the traditional (and ill-advised) dictionary.

Some other users may come with other use cases that may also help the stdlib designers choose the best solution.

Gwendal

···

Le 9 janv. 2018 à 17:16, Zach Waldowski via swift-evolution <swift-evolution@swift.org> a écrit :

Zach
zach@waldowski.me <mailto:zach@waldowski.me>

On Tue, Jan 9, 2018, at 2:12 AM, Gwendal Roué via swift-evolution wrote:

Le 9 janv. 2018 à 08:06, Gwendal Roué via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

Le 9 janv. 2018 à 06:40, Nevin Brackett-Rozinsky via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

The ulterior question of whether preserving “DictionaryLiteral” is worthwhile, is apparently out of scope. Personally, I have a hard time imagining a compelling use-case outside of the standard library, and I doubt it’s being used “in the wild” (I checked several projects in the source-compatibility suite and found zero occurrences).

DictionaryLiteral is worthwhile. The SQLite library GRDB uses DictionaryLiteral in order to build database rows (which may have duplicated column names, and whose column ordering is important). This is mostly useful for tests:

    let row = try Row.fetchOne(db, "SELECT 1 AS a, 2 AS a")!
    XCTAssertEqual(row, ["a": 1, "a": 2])

Gwendal

Chris Lattner's wrote:

why is maintaining duplicate keys a feature?

Since it is immutable, why not sort the keys in the initializer, allowing an efficient binary search to look up values?

I really wish both duplicated keys and key ordering would be preserved, since both are needed for the above sample code.

Should those features be lost, the sky wouldn't fall, that's sure. But we'd have to write something much less easy to wrote and read:

XCTAssertEqual(row.map { $0 }, [("a", 1), ("a", 2)])

Gwendal

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

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

Terms of Service

Privacy Policy

Cookie Policy