MemoryLayout for a value


(Dave Abrahams) #1

Having seen the effects in the standard library and in other
code, I'm concerned that we may have made a mistake in removing
`sizeofValue` et al without providing a replacement. In the standard
library, we ended up adding an underscored API that allows

  MemoryLayout._ofInstance(someExpression).size

Where someExpression is an autoclosure, and thus not evaluated. I
wanted to bring up the possibility of introducing a replacement as a
bufix.

I propose that the way to express the above should be:

  MemoryLayout.of(type(of: someExpression)).size

implementable as:

  extension MemoryLayout {
    @_transparent
    public
    static func of(_: T.Type) -> MemoryLayout<T>.Type {
      return MemoryLayout<T>.self
    }
  }

I think this API would solve the concerns I had about confusability that
led me to advocate dropping the ability to ask for the size of a value.
The only way to use it is to pass a type and these two expressions have
equivalent meaning:

    MemoryLayout<Int>
    MemoryLayout.of(Int.self)

It also has the benefit of isolating the autoclosure magic to type(of:).

,----[ Aside ]

A slightly cleaner use site is possible with a larger API change:

  MemoryLayout(type(of: someExpression)).size

Which would involve changing MemoryLayout from an `enum` to
a `struct` and adding the following:

  extension MemoryLayout {
    public init(_: T.Type) {}

    public var size: Int { return MemoryLayout.size }
    public var stride: Int { return MemoryLayout.stride }
    public var alignment: Int { return MemoryLayout.alignment }
  }

However I am concerned that dropping ".of" at the use site is worth the
added API complexity.

`----

Thoughts?

···

--
-Dave


(Erica Sadun) #2

I don't think using "of" is a great burden.

-- E

···

On Aug 3, 2016, at 2:43 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

Having seen the effects in the standard library and in other
code, I'm concerned that we may have made a mistake in removing
`sizeofValue` et al without providing a replacement. In the standard
library, we ended up adding an underscored API that allows

MemoryLayout._ofInstance(someExpression).size

Where someExpression is an autoclosure, and thus not evaluated. I
wanted to bring up the possibility of introducing a replacement as a
bufix.

I propose that the way to express the above should be:

MemoryLayout.of(type(of: someExpression)).size

implementable as:

extension MemoryLayout {
   @_transparent
   public
   static func of(_: T.Type) -> MemoryLayout<T>.Type {
     return MemoryLayout<T>.self
   }
}

I think this API would solve the concerns I had about confusability that
led me to advocate dropping the ability to ask for the size of a value.
The only way to use it is to pass a type and these two expressions have
equivalent meaning:

   MemoryLayout<Int>
   MemoryLayout.of(Int.self)

It also has the benefit of isolating the autoclosure magic to type(of:).

,----[ Aside ]
> A slightly cleaner use site is possible with a larger API change:
>
> MemoryLayout(type(of: someExpression)).size
>
> Which would involve changing MemoryLayout from an `enum` to
> a `struct` and adding the following:
>
> extension MemoryLayout {
> public init(_: T.Type) {}
>
> public var size: Int { return MemoryLayout.size }
> public var stride: Int { return MemoryLayout.stride }
> public var alignment: Int { return MemoryLayout.alignment }
> }
>
> However I am concerned that dropping ".of" at the use site is worth the
> added API complexity.
`----

Thoughts?
--
-Dave


(Xiaodi Wu) #3

Why not just MemoryLayout.init(of instance: T), and drop the autoclosure
magic altogether?

The classic sizeofValue evaluated its argument, and in Foundation several
uses of it actually relied on that side effect. While autoclosures are
quite clever, in general I think the user expectation is that given
`a(b(c))` both a and b are invoked, side effects and all.

Note that both type(of:) as it's currently implemented and the old
dynamicType evaluate its argument/receiver. No one afaik has ever thought
that behavior to be anomalous (though I bet we're about to hear some
arguments to that effect now).

···

On Wed, Aug 3, 2016 at 15:46 Dave Abrahams via swift-evolution < swift-evolution@swift.org> wrote:

Having seen the effects in the standard library and in other
code, I'm concerned that we may have made a mistake in removing
`sizeofValue` et al without providing a replacement. In the standard
library, we ended up adding an underscored API that allows

  MemoryLayout._ofInstance(someExpression).size

Where someExpression is an autoclosure, and thus not evaluated. I
wanted to bring up the possibility of introducing a replacement as a
bufix.

I propose that the way to express the above should be:

  MemoryLayout.of(type(of: someExpression)).size

implementable as:

  extension MemoryLayout {
    @_transparent
    public
    static func of(_: T.Type) -> MemoryLayout<T>.Type {
      return MemoryLayout<T>.self
    }
  }

I think this API would solve the concerns I had about confusability that
led me to advocate dropping the ability to ask for the size of a value.
The only way to use it is to pass a type and these two expressions have
equivalent meaning:

    MemoryLayout<Int>
    MemoryLayout.of(Int.self)

It also has the benefit of isolating the autoclosure magic to type(of:).

,----[ Aside ]
> A slightly cleaner use site is possible with a larger API change:
>
> MemoryLayout(type(of: someExpression)).size
>
> Which would involve changing MemoryLayout from an `enum` to
> a `struct` and adding the following:
>
> extension MemoryLayout {
> public init(_: T.Type) {}
>
> public var size: Int { return MemoryLayout.size }
> public var stride: Int { return MemoryLayout.stride }
> public var alignment: Int { return MemoryLayout.alignment }
> }
>
> However I am concerned that dropping ".of" at the use site is worth the
> added API complexity.
`----

Thoughts?
--
-Dave

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


(Dave Abrahams) #4

Why not just MemoryLayout.init(of instance: T), and drop the autoclosure
magic altogether?

My proposal *does* drop the autoclosure magic. `type(of: x)` is already in
the standard library (replacing `x.dynamicType`). The reasons not to have:

   MemoryLayout(of: x)

where x is an arbitrary instance, is that it reads and pronounces the
same as

   MemoryLayout<X>

but has different meaning, and even a different type (which results in
additional API complexity—the forwarding vars I showed in the [Aside]
box from my previous post). Imagine explaining the difference between
these two in that world:

   MemoryLayout<Int>
   MemoryLayout(of: Int.self)

The first is a type representing the layout of Int. The second is an
instance of that type representing the layout of Int's metatype.

The classic sizeofValue evaluated its argument, and in Foundation several
uses of it actually relied on that side effect. While autoclosures are
quite clever, in general I think the user expectation is that given
`a(b(c))` both a and b are invoked, side effects and all.

Note that both type(of:) as it's currently implemented and the old
dynamicType evaluate its argument/receiver.

I didn't realize that, but it's fine. I'm attached to the use of
`type(of:)` in this idiom, not to having an autoclosure involved.

···

on Wed Aug 03 2016, Xiaodi Wu <xiaodi.wu-AT-gmail.com> wrote:

No one afaik has ever thought that behavior to be anomalous (though I
bet we're about to hear some arguments to that effect now).

On Wed, Aug 3, 2016 at 15:46 Dave Abrahams via swift-evolution < > swift-evolution@swift.org> wrote:

Having seen the effects in the standard library and in other
code, I'm concerned that we may have made a mistake in removing
`sizeofValue` et al without providing a replacement. In the standard
library, we ended up adding an underscored API that allows

  MemoryLayout._ofInstance(someExpression).size

Where someExpression is an autoclosure, and thus not evaluated. I
wanted to bring up the possibility of introducing a replacement as a
bufix.

I propose that the way to express the above should be:

  MemoryLayout.of(type(of: someExpression)).size

implementable as:

  extension MemoryLayout {
    @_transparent
    public
    static func of(_: T.Type) -> MemoryLayout<T>.Type {
      return MemoryLayout<T>.self
    }
  }

I think this API would solve the concerns I had about confusability that
led me to advocate dropping the ability to ask for the size of a value.
The only way to use it is to pass a type and these two expressions have
equivalent meaning:

    MemoryLayout<Int>
    MemoryLayout.of(Int.self)

It also has the benefit of isolating the autoclosure magic to type(of:).

,----[ Aside ]
> A slightly cleaner use site is possible with a larger API change:
>
> MemoryLayout(type(of: someExpression)).size
>
> Which would involve changing MemoryLayout from an `enum` to
> a `struct` and adding the following:
>
> extension MemoryLayout {
> public init(_: T.Type) {}
>
> public var size: Int { return MemoryLayout.size }
> public var stride: Int { return MemoryLayout.stride }
> public var alignment: Int { return MemoryLayout.alignment }
> }
>
> However I am concerned that dropping ".of" at the use site is worth the
> added API complexity.
`----

Thoughts?
--
-Dave

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

--
-Dave


(Xiaodi Wu) #5

>
>
> Having seen the effects in the standard library and in other
> code, I'm concerned that we may have made a mistake in removing
> `sizeofValue` et al without providing a replacement. In the standard
> library, we ended up adding an underscored API that allows
>
> MemoryLayout._ofInstance(someExpression).size
>
> Where someExpression is an autoclosure, and thus not evaluated. I
> wanted to bring up the possibility of introducing a replacement as a
> bufix.
>
> I propose that the way to express the above should be:
>
> MemoryLayout.of(type(of: someExpression)).size
>
> implementable as:
>
> extension MemoryLayout {
> @_transparent
> public
> static func of(_: T.Type) -> MemoryLayout<T>.Type {
> return MemoryLayout<T>.self
> }
> }
>
> I think this API would solve the concerns I had about confusability that
> led me to advocate dropping the ability to ask for the size of a value.
> The only way to use it is to pass a type and these two expressions have
> equivalent meaning:
>
> MemoryLayout<Int>
> MemoryLayout.of(Int.self)
>
> It also has the benefit of isolating the autoclosure magic to type(of:).
>
> ,----[ Aside ]
> > A slightly cleaner use site is possible with a larger API change:
> >
> > MemoryLayout(type(of: someExpression)).size
> >
> > Which would involve changing MemoryLayout from an `enum` to
> > a `struct` and adding the following:
> >
> > extension MemoryLayout {
> > public init(_: T.Type) {}
> >
> > public var size: Int { return MemoryLayout.size }
> > public var stride: Int { return MemoryLayout.stride }
> > public var alignment: Int { return MemoryLayout.alignment }
> > }
> >
> > However I am concerned that dropping ".of" at the use site is worth the
> > added API complexity.
> `----
>
> Thoughts?
> --
> -Dave

I don't think using "of" is a great burden.

Agreed, but I do think "memory layout of type of my value, size" is a
mouthful compared to "size of value". Moreover, something doesn't sit right
with me that MemoryLayout<T> and MemoryLayout.of(T.self) would be one and
the same thing.

Could I suggest an alternative? It's conservative in that it mimics the
relationships we had before the proposal was implemented and also maintains
the simplicity of the caseless enum:

extension MemoryLayout {
  static func size(ofValue _: T) -> Int { return MemoryLayout.size }
  // etc.
}
···

On Wed, Aug 3, 2016 at 8:47 PM, Erica Sadun via swift-evolution < swift-evolution@swift.org> wrote:

> On Aug 3, 2016, at 2:43 PM, Dave Abrahams via swift-evolution < > swift-evolution@swift.org> wrote:

-- E

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


(Xiaodi Wu) #6

> Why not just MemoryLayout.init(of instance: T), and drop the autoclosure
> magic altogether?

My proposal *does* drop the autoclosure magic. `type(of: x)` is already in
the standard library (replacing `x.dynamicType`). The reasons not to have:

   MemoryLayout(of: x)

where x is an arbitrary instance, is that it reads and pronounces the
same as

   MemoryLayout<X>

but has different meaning, and even a different type (which results in
additional API complexity—the forwarding vars I showed in the [Aside]
box from my previous post). Imagine explaining the difference between
these two in that world:

   MemoryLayout<Int>
   MemoryLayout(of: Int.self)

The first is a type representing the layout of Int. The second is an
instance of that type representing the layout of Int's metatype.

> The classic sizeofValue evaluated its argument, and in Foundation several
> uses of it actually relied on that side effect. While autoclosures are
> quite clever, in general I think the user expectation is that given
> `a(b(c))` both a and b are invoked, side effects and all.
>
> Note that both type(of:) as it's currently implemented and the old
> dynamicType evaluate its argument/receiver.

I didn't realize that, but it's fine. I'm attached to the use of
`type(of:)` in this idiom, not to having an autoclosure involved.

Your proposed `.of(type(of: x)).size` differs from the original
`sizeofValue()` in at least one other way--is this in fact *why* you're
proposing the change? In the classic syntax:

protocol P { }
print(sizeof(P.self)) // 40

struct S : P {
  let x = 2
}
print(sizeof(S.self)) // 8

var a: P = S()
print(a.dynamicType) // S
print(sizeofValue(a)) // 40
···

On Wed, Aug 3, 2016 at 11:27 PM, Dave Abrahams <dabrahams@apple.com> wrote:

on Wed Aug 03 2016, Xiaodi Wu <xiaodi.wu-AT-gmail.com> wrote:

No one afaik has ever thought that behavior to be anomalous (though I
> bet we're about to hear some arguments to that effect now).
>
> On Wed, Aug 3, 2016 at 15:46 Dave Abrahams via swift-evolution < > > swift-evolution@swift.org> wrote:
>
>>
>> Having seen the effects in the standard library and in other
>> code, I'm concerned that we may have made a mistake in removing
>> `sizeofValue` et al without providing a replacement. In the standard
>> library, we ended up adding an underscored API that allows
>>
>> MemoryLayout._ofInstance(someExpression).size
>>
>> Where someExpression is an autoclosure, and thus not evaluated. I
>> wanted to bring up the possibility of introducing a replacement as a
>> bufix.
>>
>> I propose that the way to express the above should be:
>>
>> MemoryLayout.of(type(of: someExpression)).size
>>
>> implementable as:
>>
>> extension MemoryLayout {
>> @_transparent
>> public
>> static func of(_: T.Type) -> MemoryLayout<T>.Type {
>> return MemoryLayout<T>.self
>> }
>> }
>>
>> I think this API would solve the concerns I had about confusability that
>> led me to advocate dropping the ability to ask for the size of a value.
>> The only way to use it is to pass a type and these two expressions have
>> equivalent meaning:
>>
>> MemoryLayout<Int>
>> MemoryLayout.of(Int.self)
>>
>> It also has the benefit of isolating the autoclosure magic to type(of:).
>>
>> ,----[ Aside ]
>> > A slightly cleaner use site is possible with a larger API change:
>> >
>> > MemoryLayout(type(of: someExpression)).size
>> >
>> > Which would involve changing MemoryLayout from an `enum` to
>> > a `struct` and adding the following:
>> >
>> > extension MemoryLayout {
>> > public init(_: T.Type) {}
>> >
>> > public var size: Int { return MemoryLayout.size }
>> > public var stride: Int { return MemoryLayout.stride }
>> > public var alignment: Int { return MemoryLayout.alignment }
>> > }
>> >
>> > However I am concerned that dropping ".of" at the use site is worth
the
>> > added API complexity.
>> `----
>>
>> Thoughts?
>> --
>> -Dave
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>

--
-Dave


(Karl) #7

Why not just MemoryLayout.init(of instance: T), and drop the autoclosure
magic altogether?

My proposal *does* drop the autoclosure magic. `type(of: x)` is already in
the standard library (replacing `x.dynamicType`). The reasons not to have:

  MemoryLayout(of: x)

where x is an arbitrary instance, is that it reads and pronounces the
same as

  MemoryLayout<X>

but has different meaning, and even a different type (which results in
additional API complexity—the forwarding vars I showed in the [Aside]
box from my previous post). Imagine explaining the difference between
these two in that world:

  MemoryLayout<Int>
  MemoryLayout(of: Int.self)

The first is a type representing the layout of Int. The second is an
instance of that type representing the layout of Int's metatype.

It’s confusing because metatypes in Swift are pretty confusing in general: Int.self returns Int.Type which is not the same as `type(of: <some Int>)` (that would be Int).

If a novice wants to jump in, they’ll have to know that MemoryLayout(of: Int.self) would return a MemoryLayout<Int.Type>.

···

On 4 Aug 2016, at 06:27, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
on Wed Aug 03 2016, Xiaodi Wu <xiaodi.wu-AT-gmail.com <http://xiaodi.wu-at-gmail.com/>> wrote:

The classic sizeofValue evaluated its argument, and in Foundation several
uses of it actually relied on that side effect. While autoclosures are
quite clever, in general I think the user expectation is that given
`a(b(c))` both a and b are invoked, side effects and all.

Note that both type(of:) as it's currently implemented and the old
dynamicType evaluate its argument/receiver.

I didn't realize that, but it's fine. I'm attached to the use of
`type(of:)` in this idiom, not to having an autoclosure involved.

No one afaik has ever thought that behavior to be anomalous (though I
bet we're about to hear some arguments to that effect now).

On Wed, Aug 3, 2016 at 15:46 Dave Abrahams via swift-evolution < >> swift-evolution@swift.org> wrote:

Having seen the effects in the standard library and in other
code, I'm concerned that we may have made a mistake in removing
`sizeofValue` et al without providing a replacement. In the standard
library, we ended up adding an underscored API that allows

MemoryLayout._ofInstance(someExpression).size

Where someExpression is an autoclosure, and thus not evaluated. I
wanted to bring up the possibility of introducing a replacement as a
bufix.

I propose that the way to express the above should be:

MemoryLayout.of(type(of: someExpression)).size

implementable as:

extension MemoryLayout {
   @_transparent
   public
   static func of(_: T.Type) -> MemoryLayout<T>.Type {
     return MemoryLayout<T>.self
   }
}

I think this API would solve the concerns I had about confusability that
led me to advocate dropping the ability to ask for the size of a value.
The only way to use it is to pass a type and these two expressions have
equivalent meaning:

   MemoryLayout<Int>
   MemoryLayout.of(Int.self)

It also has the benefit of isolating the autoclosure magic to type(of:).

,----[ Aside ]
> A slightly cleaner use site is possible with a larger API change:
>
> MemoryLayout(type(of: someExpression)).size
>
> Which would involve changing MemoryLayout from an `enum` to
> a `struct` and adding the following:
>
> extension MemoryLayout {
> public init(_: T.Type) {}
>
> public var size: Int { return MemoryLayout.size }
> public var stride: Int { return MemoryLayout.stride }
> public var alignment: Int { return MemoryLayout.alignment }
> }
>
> However I am concerned that dropping ".of" at the use site is worth the
> added API complexity.
`----

Thoughts?
--
-Dave

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

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


(Dave Abrahams) #8

Agreed, but I do think "memory layout of type of my value, size" is a
mouthful compared to "size of value".

It is, but it would avoid confusion.

Moreover, something doesn't sit right with me that MemoryLayout<T> and
MemoryLayout.of(T.self) would be one and the same thing.

As far as I'm concerned, that's a feature, not a bug. Unless you can
describe why it should be different, “it doesn't sit right” is not a
helpful argument.

Could I suggest an alternative? It's conservative in that it mimics the
relationships we had before the proposal was implemented and also maintains
the simplicity of the caseless enum:

extension MemoryLayout {
  static func size(ofValue _: T) -> Int { return MemoryLayout.size }
  // etc.
}

That introduces even more potential for confusion than adding forwarding
vars to instances does. Now you're talking about “overloading” a static
property with a static method having the same base name.

···

on Wed Aug 03 2016, Xiaodi Wu <xiaodi.wu-AT-gmail.com> wrote:

--
-Dave


(Xiaodi Wu) #9

Why not just MemoryLayout.init(of instance: T), and drop the autoclosure
magic altogether?

My proposal *does* drop the autoclosure magic. `type(of: x)` is already in
the standard library (replacing `x.dynamicType`). The reasons not to have:

  MemoryLayout(of: x)

where x is an arbitrary instance, is that it reads and pronounces the
same as

  MemoryLayout<X>

but has different meaning, and even a different type (which results in
additional API complexity—the forwarding vars I showed in the [Aside]
box from my previous post). Imagine explaining the difference between
these two in that world:

  MemoryLayout<Int>
  MemoryLayout(of: Int.self)

The first is a type representing the layout of Int. The second is an
instance of that type representing the layout of Int's metatype.

It’s confusing because metatypes in Swift are pretty confusing in general:
Int.self returns Int.Type which is not the same as `type(of: <some Int>)`
(that would be Int).

If a novice wants to jump in, they’ll have to know that MemoryLayout(of:
Int.self) would return a MemoryLayout<Int.Type>.

Yes, here, I agree Dave is absolutely right. You and Dave have convinced me
that neither `MemoryLayout(of: x)` nor `MemoryLayout.of(x)`, where x is an
instance, would be appropriate.

···

On Thu, Aug 4, 2016 at 2:29 AM, Karl <razielim@gmail.com> wrote:

On 4 Aug 2016, at 06:27, Dave Abrahams via swift-evolution < > swift-evolution@swift.org> wrote:
on Wed Aug 03 2016, Xiaodi Wu <xiaodi.wu-AT-gmail.com > <http://xiaodi.wu-at-gmail.com/>> wrote:

The classic sizeofValue evaluated its argument, and in Foundation several
uses of it actually relied on that side effect. While autoclosures are
quite clever, in general I think the user expectation is that given
`a(b(c))` both a and b are invoked, side effects and all.

Note that both type(of:) as it's currently implemented and the old
dynamicType evaluate its argument/receiver.

I didn't realize that, but it's fine. I'm attached to the use of
`type(of:)` in this idiom, not to having an autoclosure involved.

No one afaik has ever thought that behavior to be anomalous (though I
bet we're about to hear some arguments to that effect now).

On Wed, Aug 3, 2016 at 15:46 Dave Abrahams via swift-evolution < > swift-evolution@swift.org> wrote:

Having seen the effects in the standard library and in other
code, I'm concerned that we may have made a mistake in removing
`sizeofValue` et al without providing a replacement. In the standard
library, we ended up adding an underscored API that allows

MemoryLayout._ofInstance(someExpression).size

Where someExpression is an autoclosure, and thus not evaluated. I
wanted to bring up the possibility of introducing a replacement as a
bufix.

I propose that the way to express the above should be:

MemoryLayout.of(type(of: someExpression)).size

implementable as:

extension MemoryLayout {
   @_transparent
   public
   static func of(_: T.Type) -> MemoryLayout<T>.Type {
     return MemoryLayout<T>.self
   }
}

I think this API would solve the concerns I had about confusability that
led me to advocate dropping the ability to ask for the size of a value.
The only way to use it is to pass a type and these two expressions have
equivalent meaning:

   MemoryLayout<Int>
   MemoryLayout.of(Int.self)

It also has the benefit of isolating the autoclosure magic to type(of:).

,----[ Aside ]
> A slightly cleaner use site is possible with a larger API change:
>
> MemoryLayout(type(of: someExpression)).size
>
> Which would involve changing MemoryLayout from an `enum` to
> a `struct` and adding the following:
>
> extension MemoryLayout {
> public init(_: T.Type) {}
>
> public var size: Int { return MemoryLayout.size }
> public var stride: Int { return MemoryLayout.stride }
> public var alignment: Int { return MemoryLayout.alignment }
> }
>
> However I am concerned that dropping ".of" at the use site is worth the
> added API complexity.
`----

Thoughts?
--
-Dave

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

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


(Boris Wang) #10

excuse me, does this means there no sizeof(), like C language?

In C:

Struct S {}

Let x= S()

size of(S) == size of(x)

Xiaodi Wu via swift-evolution <swift-evolution@swift.org>于2016年8月4日
周四15:32写道:

···

On Thu, Aug 4, 2016 at 2:29 AM, Karl <razielim@gmail.com> wrote:

On 4 Aug 2016, at 06:27, Dave Abrahams via swift-evolution < >> swift-evolution@swift.org> wrote:

on Wed Aug 03 2016, Xiaodi Wu <xiaodi.wu-AT-gmail.com >> <http://xiaodi.wu-at-gmail.com/>> wrote:

Why not just MemoryLayout.init(of instance: T), and drop the autoclosure
magic altogether?

My proposal *does* drop the autoclosure magic. `type(of: x)` is already
in
the standard library (replacing `x.dynamicType`). The reasons not to have:

  MemoryLayout(of: x)

where x is an arbitrary instance, is that it reads and pronounces the
same as

  MemoryLayout<X>

but has different meaning, and even a different type (which results in
additional API complexity—the forwarding vars I showed in the [Aside]
box from my previous post). Imagine explaining the difference between
these two in that world:

  MemoryLayout<Int>
  MemoryLayout(of: Int.self)

The first is a type representing the layout of Int. The second is an
instance of that type representing the layout of Int's metatype.

It’s confusing because metatypes in Swift are pretty confusing in
general: Int.self returns Int.Type which is not the same as `type(of: <some
>)` (that would be Int).

If a novice wants to jump in, they’ll have to know that MemoryLayout(of:
Int.self) would return a MemoryLayout<Int.Type>.

Yes, here, I agree Dave is absolutely right. You and Dave have convinced
me that neither `MemoryLayout(of: x)` nor `MemoryLayout.of(x)`, where x is
an instance, would be appropriate.

The classic sizeofValue evaluated its argument, and in Foundation several
uses of it actually relied on that side effect. While autoclosures are
quite clever, in general I think the user expectation is that given
`a(b(c))` both a and b are invoked, side effects and all.

Note that both type(of:) as it's currently implemented and the old
dynamicType evaluate its argument/receiver.

I didn't realize that, but it's fine. I'm attached to the use of
`type(of:)` in this idiom, not to having an autoclosure involved.

No one afaik has ever thought that behavior to be anomalous (though I
bet we're about to hear some arguments to that effect now).

On Wed, Aug 3, 2016 at 15:46 Dave Abrahams via swift-evolution < >> swift-evolution@swift.org> wrote:

Having seen the effects in the standard library and in other
code, I'm concerned that we may have made a mistake in removing
`sizeofValue` et al without providing a replacement. In the standard
library, we ended up adding an underscored API that allows

MemoryLayout._ofInstance(someExpression).size

Where someExpression is an autoclosure, and thus not evaluated. I
wanted to bring up the possibility of introducing a replacement as a
bufix.

I propose that the way to express the above should be:

MemoryLayout.of(type(of: someExpression)).size

implementable as:

extension MemoryLayout {
   @_transparent
   public
   static func of(_: T.Type) -> MemoryLayout<T>.Type {
     return MemoryLayout<T>.self
   }
}

I think this API would solve the concerns I had about confusability that
led me to advocate dropping the ability to ask for the size of a value.
The only way to use it is to pass a type and these two expressions have
equivalent meaning:

   MemoryLayout<Int>
   MemoryLayout.of(Int.self)

It also has the benefit of isolating the autoclosure magic to type(of:).

,----[ Aside ]
> A slightly cleaner use site is possible with a larger API change:
>
> MemoryLayout(type(of: someExpression)).size
>
> Which would involve changing MemoryLayout from an `enum` to
> a `struct` and adding the following:
>
> extension MemoryLayout {
> public init(_: T.Type) {}
>
> public var size: Int { return MemoryLayout.size }
> public var stride: Int { return MemoryLayout.stride }
> public var alignment: Int { return MemoryLayout.alignment }
> }
>
> However I am concerned that dropping ".of" at the use site is worth the
> added API complexity.
`----

Thoughts?
--
-Dave

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

--
-Dave
_______________________________________________
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


(Dmitri Gribenko) #11

I like this API. I think given all the alternatives that we explored,
it is better than those. I also think that it nicely avoids the
following issue with the proposed MemoryLayout.of(type(of:
someExpression)).size syntax.

Imagine that you have a value whose static type differs from the
dynamic type. For example, a protocol existential:

protocol P {}
extension Int : P {}
var x: P = 10

The question is, what does MemoryLayout.of(type(of: x)).size compute,
size of the existential box, or the size of an Int instance? The
semantics of 'type(of:)' are "return the dynamic type", so the
straightforward conclusion is that MemoryLayout.of(type(of: x)).size
returns the size of the dynamic type instance, of Int.

What actually happens is that 'type(of: x)' returns a dynamic value of
'Int.self', statically typed as 'P.Type'. So P gets deduced for the
generic parameter of MemoryLayout, and MemoryLayout.of(type(of:
x)).size returns the size of the protocol box.

I think due to this complex interaction, using type(of:) might lead to
confusing code, and thus I like Xiaodi's approach better.

Dmitri

···

On Wed, Aug 3, 2016 at 7:28 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

Could I suggest an alternative? It's conservative in that it mimics the
relationships we had before the proposal was implemented and also maintains
the simplicity of the caseless enum:

extension MemoryLayout {
  static func size(ofValue _: T) -> Int { return MemoryLayout.size }
  // etc.
}

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/


(Anton Zhilin) #12

Two weeks ago Adrian and I suggested adding dynamic 'size', 'stride',
'alignment' to Mirror, which definition would look like:

public struct Mirror {
    internal metatype_: Any.Type

    public init<T>(_: T.Type)

    public var size: Int { get }
    public var stride: Int { get }
    public var align: Int { get }

    // ...
}

There are some problems with it right now, but I do believe that reflection
API is where dynamic `size`, `stride`, `alignment` belong.

···

2016-08-04 10:31 GMT+03:00 Xiaodi Wu via swift-evolution < swift-evolution@swift.org>:

On Thu, Aug 4, 2016 at 2:29 AM, Karl <razielim@gmail.com> wrote:

It’s confusing because metatypes in Swift are pretty confusing in
general: Int.self returns Int.Type which is not the same as `type(of: <some
>)` (that would be Int).

If a novice wants to jump in, they’ll have to know that MemoryLayout(of:
Int.self) would return a MemoryLayout<Int.Type>.

Yes, here, I agree Dave is absolutely right. You and Dave have convinced
me that neither `MemoryLayout(of: x)` nor `MemoryLayout.of(x)`, where x is
an instance, would be appropriate.


#13
extension MemoryLayout {
  static func size(ofValue _: T) -> Int { return MemoryLayout.size }
  // etc.
}

I don't think we can do this while we have:

  public static var size: Int {

maybe `sizeOf(value _: T) -> Int` ?

···

2016-08-04 11:28 GMT+09:00 Xiaodi Wu via swift-evolution < swift-evolution@swift.org>:

On Wed, Aug 3, 2016 at 8:47 PM, Erica Sadun via swift-evolution < > swift-evolution@swift.org> wrote:

> On Aug 3, 2016, at 2:43 PM, Dave Abrahams via swift-evolution < >> swift-evolution@swift.org> wrote:
>
>
> Having seen the effects in the standard library and in other
> code, I'm concerned that we may have made a mistake in removing
> `sizeofValue` et al without providing a replacement. In the standard
> library, we ended up adding an underscored API that allows
>
> MemoryLayout._ofInstance(someExpression).size
>
> Where someExpression is an autoclosure, and thus not evaluated. I
> wanted to bring up the possibility of introducing a replacement as a
> bufix.
>
> I propose that the way to express the above should be:
>
> MemoryLayout.of(type(of: someExpression)).size
>
> implementable as:
>
> extension MemoryLayout {
> @_transparent
> public
> static func of(_: T.Type) -> MemoryLayout<T>.Type {
> return MemoryLayout<T>.self
> }
> }
>
> I think this API would solve the concerns I had about confusability that
> led me to advocate dropping the ability to ask for the size of a value.
> The only way to use it is to pass a type and these two expressions have
> equivalent meaning:
>
> MemoryLayout<Int>
> MemoryLayout.of(Int.self)
>
> It also has the benefit of isolating the autoclosure magic to type(of:).
>
> ,----[ Aside ]
> > A slightly cleaner use site is possible with a larger API change:
> >
> > MemoryLayout(type(of: someExpression)).size
> >
> > Which would involve changing MemoryLayout from an `enum` to
> > a `struct` and adding the following:
> >
> > extension MemoryLayout {
> > public init(_: T.Type) {}
> >
> > public var size: Int { return MemoryLayout.size }
> > public var stride: Int { return MemoryLayout.stride }
> > public var alignment: Int { return MemoryLayout.alignment }
> > }
> >
> > However I am concerned that dropping ".of" at the use site is worth
the
> > added API complexity.
> `----
>
> Thoughts?
> --
> -Dave

I don't think using "of" is a great burden.

Agreed, but I do think "memory layout of type of my value, size" is a
mouthful compared to "size of value". Moreover, something doesn't sit right
with me that MemoryLayout<T> and MemoryLayout.of(T.self) would be one and
the same thing.

Could I suggest an alternative? It's conservative in that it mimics the
relationships we had before the proposal was implemented and also maintains
the simplicity of the caseless enum:

extension MemoryLayout {
  static func size(ofValue _: T) -> Int { return MemoryLayout.size }
  // etc.
}

-- E

_______________________________________________
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


(Xiaodi Wu) #14

> Agreed, but I do think "memory layout of type of my value, size" is a
> mouthful compared to "size of value".

It is, but it would avoid confusion.

> Moreover, something doesn't sit right with me that MemoryLayout<T> and
> MemoryLayout.of(T.self) would be one and the same thing.

As far as I'm concerned, that's a feature, not a bug. Unless you can
describe why it should be different, “it doesn't sit right” is not a
helpful argument.

Originally, I'd actually half-way typed out a fuller argument, then deleted
it, assuming most would find it to be uninteresting due to obviousness.
Let's see:

Unless I'm mistaken, every place where one might write `MemoryLayout<T>`
can be replaced with `MemoryLayout.of(T.self)`. (Yes, I understand that
there are places where substituting in the other direction would be
unsatisfactory, hence this follow-up thread.) However, I understand it to
be a bug, not a feature, to have two different ways of spelling the same
thing, because it necessarily brings confusion as to why there must be two
of them, and I therefore consider this proposed design to be suboptimal.
You titled this thread "MemoryLayout for a value": I agree that that's what
we need. It ought to be possible to provide facilities for exactly that
*without* also providing an entirely duplicative way of spelling
MemoryLayout for a type.

Could I suggest an alternative? It's conservative in that it mimics the
> relationships we had before the proposal was implemented and also
maintains
> the simplicity of the caseless enum:
>
> ```
> extension MemoryLayout {
> static func size(ofValue _: T) -> Int { return MemoryLayout.size }
> // etc.
> }
> ```

That introduces even more potential for confusion than adding forwarding
vars to instances does. Now you're talking about “overloading” a static
property with a static method having the same base name.

IMO, here's where it's a feature, not a bug. I propose `size(ofValue:)` and
`size` because they *are* related, just like how `first(where:)` and
`first` are related for a Collection. Moreover, the whole thing reads
exactly as it should (and, not by accident, nearly identically to this
thread's subject line): "memory layout size of value x". What is the source
of confusion that you think would arise from this pseudo-overloading, and
why are you emphasizing the fact that both would be static
properties/methods (is it less confusing when it's not static)?

···

On Wed, Aug 3, 2016 at 11:32 PM, Dave Abrahams <dabrahams@apple.com> wrote:

on Wed Aug 03 2016, Xiaodi Wu <xiaodi.wu-AT-gmail.com> wrote:

--
-Dave


(Dave Abrahams) #15

I see your point, but that would unfortunately be an unacceptably
expensive way to get that information. Constructing a mirror is a
nontrivial bit of work.

···

on Thu Aug 04 2016, Anton Zhilin <antonyzhilin-AT-gmail.com> wrote:

2016-08-04 10:31 GMT+03:00 Xiaodi Wu via swift-evolution <
swift-evolution@swift.org>:

On Thu, Aug 4, 2016 at 2:29 AM, Karl <razielim@gmail.com> wrote:

It’s confusing because metatypes in Swift are pretty confusing in
general: Int.self returns Int.Type which is not the same as `type(of: <some
>)` (that would be Int).

If a novice wants to jump in, they’ll have to know that MemoryLayout(of:
Int.self) would return a MemoryLayout<Int.Type>.

Yes, here, I agree Dave is absolutely right. You and Dave have convinced
me that neither `MemoryLayout(of: x)` nor `MemoryLayout.of(x)`, where x is
an instance, would be appropriate.

Two weeks ago Adrian and I suggested adding dynamic 'size', 'stride',
'alignment' to Mirror, which definition would look like:

public struct Mirror {
    internal metatype_: Any.Type

    public init<T>(_: T.Type)

    public var size: Int { get }
    public var stride: Int { get }
    public var align: Int { get }

    // ...
}

There are some problems with it right now, but I do believe that reflection
API is where dynamic `size`, `stride`, `alignment` belong.

--
-Dave


(Dave Abrahams) #16

I don't know. IMO none of these questions can be answered in time to
solve the cited problem for Swift 3.

···

on Thu Aug 04 2016, David Sweeris <davesweeris-AT-mac.com> wrote:

On Aug 4, 2016, at 13:31, Dave Abrahams via swift-evolution >> <swift-evolution@swift.org> wrote:

on Thu Aug 04 2016, Anton Zhilin <antonyzhilin-AT-gmail.com> wrote:

2016-08-04 10:31 GMT+03:00 Xiaodi Wu via swift-evolution <
swift-evolution@swift.org>:

On Thu, Aug 4, 2016 at 2:29 AM, Karl <razielim@gmail.com> wrote:

It’s confusing because metatypes in Swift are pretty confusing in
general: Int.self returns Int.Type which is not the same as `type(of: <some
>)` (that would be Int).

If a novice wants to jump in, they’ll have to know that MemoryLayout(of:
Int.self) would return a MemoryLayout<Int.Type>.

Yes, here, I agree Dave is absolutely right. You and Dave have convinced
me that neither `MemoryLayout(of: x)` nor `MemoryLayout.of(x)`, where x is
an instance, would be appropriate.

Two weeks ago Adrian and I suggested adding dynamic 'size', 'stride',
'alignment' to Mirror, which definition would look like:

public struct Mirror {
   internal metatype_: Any.Type

   public init<T>(_: T.Type)

   public var size: Int { get }
   public var stride: Int { get }
   public var align: Int { get }

   // ...
}

There are some problems with it right now, but I do believe that reflection
API is where dynamic `size`, `stride`, `alignment` belong.

I see your point, but that would unfortunately be an unacceptably
expensive way to get that information. Constructing a mirror is a
nontrivial bit of work.

Two quick questions:
1) Can the expensive bits of mirrors be done lazily?
2) IIRC, the reflection API is supposed to be reworked for Swift
4. With that in mind, are mirrors likely to remain too be expensive to
construct for this approach?

--
-Dave


(David Sweeris) #17

Two quick questions:
1) Can the expensive bits of mirrors be done lazily?
2) IIRC, the reflection API is supposed to be reworked for Swift 4. With that in mind, are mirrors likely to remain too be expensive to construct for this approach?

- Dave Sweeris

···

On Aug 4, 2016, at 13:31, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:

on Thu Aug 04 2016, Anton Zhilin <antonyzhilin-AT-gmail.com> wrote:

2016-08-04 10:31 GMT+03:00 Xiaodi Wu via swift-evolution <
swift-evolution@swift.org>:

On Thu, Aug 4, 2016 at 2:29 AM, Karl <razielim@gmail.com> wrote:

It’s confusing because metatypes in Swift are pretty confusing in
general: Int.self returns Int.Type which is not the same as `type(of: <some
>)` (that would be Int).

If a novice wants to jump in, they’ll have to know that MemoryLayout(of:
Int.self) would return a MemoryLayout<Int.Type>.

Yes, here, I agree Dave is absolutely right. You and Dave have convinced
me that neither `MemoryLayout(of: x)` nor `MemoryLayout.of(x)`, where x is
an instance, would be appropriate.

Two weeks ago Adrian and I suggested adding dynamic 'size', 'stride',
'alignment' to Mirror, which definition would look like:

public struct Mirror {
   internal metatype_: Any.Type

   public init<T>(_: T.Type)

   public var size: Int { get }
   public var stride: Int { get }
   public var align: Int { get }

   // ...
}

There are some problems with it right now, but I do believe that reflection
API is where dynamic `size`, `stride`, `alignment` belong.

I see your point, but that would unfortunately be an unacceptably
expensive way to get that information. Constructing a mirror is a
nontrivial bit of work.


(Dave Abrahams) #18

Okay, I'm convinced; that's what we should do.

···

on Thu Aug 04 2016, Dmitri Gribenko <gribozavr-AT-gmail.com> wrote:

On Wed, Aug 3, 2016 at 7:28 PM, Xiaodi Wu via swift-evolution > <swift-evolution@swift.org> wrote:

Could I suggest an alternative? It's conservative in that it mimics the
relationships we had before the proposal was implemented and also maintains
the simplicity of the caseless enum:

extension MemoryLayout {
  static func size(ofValue _: T) -> Int { return MemoryLayout.size }
  // etc.
}

I like this API. I think given all the alternatives that we explored,
it is better than those. I also think that it nicely avoids the
following issue with the proposed MemoryLayout.of(type(of:
someExpression)).size syntax.

Imagine that you have a value whose static type differs from the
dynamic type. For example, a protocol existential:

protocol P {}
extension Int : P {}
var x: P = 10

The question is, what does MemoryLayout.of(type(of: x)).size compute,
size of the existential box, or the size of an Int instance? The
semantics of 'type(of:)' are "return the dynamic type", so the
straightforward conclusion is that MemoryLayout.of(type(of: x)).size
returns the size of the dynamic type instance, of Int.

What actually happens is that 'type(of: x)' returns a dynamic value of
'Int.self', statically typed as 'P.Type'. So P gets deduced for the
generic parameter of MemoryLayout, and MemoryLayout.of(type(of:
x)).size returns the size of the protocol box.

I think due to this complex interaction, using type(of:) might lead to
confusing code, and thus I like Xiaodi's approach better.

Dmitri

--
-Dave


(Anton Zhilin) #19

I don't mean current heavyweight Mirror. Call that type ReflectionWrapper,
if you want. It would only contain 'Any.Type' stored property.
Largest of 'problems' that I meant is that reflection is postponed, and my
type would look odd without full reflection capabilities (only with 'size'
and friends).

···

2016-08-04 21:31 GMT+03:00 Dave Abrahams <dabrahams@apple.com>:

on Thu Aug 04 2016, Anton Zhilin <antonyzhilin-AT-gmail.com> wrote:
> Two weeks ago Adrian and I suggested adding dynamic 'size', 'stride',
> 'alignment' to Mirror, which definition would look like:
>
> public struct ReflectionWrapper { // fixed!
> internal metatype_: Any.Type
>
> public init<T>(_: T.Type)
>
> public var size: Int { get }
> public var stride: Int { get }
> public var align: Int { get }
>
> // ...
> }
>
> There are some problems with it right now, but I do believe that
reflection
> API is where dynamic `size`, `stride`, `alignment` belong.

I see your point, but that would unfortunately be an unacceptably
expensive way to get that information. Constructing a mirror is a
nontrivial bit of work.


(Anton Zhilin) #20

First is not really a problem, but we need reflection in place for my
suggestion. If we are going for a "quick fix", then we can't wait for full
API designed. I have to agree with Dave on that matter.

···

2016-08-04 21:42 GMT+03:00 David Sweeris <davesweeris@mac.com>:

Two quick questions:
1) Can the expensive bits of mirrors be done lazily?
2) IIRC, the reflection API is supposed to be reworked for Swift 4. With
that in mind, are mirrors likely to remain too be expensive to construct
for this approach?

- Dave Sweeris