Why inout protocol parameter in function work with strange


#1

Hello. I have protocol witch allow type to handle it's position and function who handle this position and compiler get me error. Please, tell, Why I can not use protocol name in inout function? The example here.

protocol Position {
var x: Double { get set }
}

struct Car: Position {
var x: Double
}

func move(item: inout Position ) {
item. x += 1
}

var car = Car (x: 50 )

move (item: & car ) \\ cannot pass immutable value as inout argument: implicit conversion from 'Car' to 'Position' requires a temporary

···

--
Седых Александр


(Guillaume Lessard) #2

In your example, the compiler needs a parameter of type Position. Car is a type of Position, but they are not interchangeable. See below:

protocol Position {
    var x: Double { getset }
}

struct Car: Position {
    var x: Double
}

func move(item: inout Position) {
    item.x += 1
}

var car = Car(x: 50)

var pos: Position = car

move(item: &pos) // this works.
assert(pos.x == 51) // works

The move function as you wrote it requires the memory representation of a Position variable, which Car does not have; when you assign it to a Position variable, the Car struct gets accessed through an indirection layer. (There was a WWDC talk about this last year or the year before.)

You may want a generic function instead:

func move<P: Position>(item: inout P) {
  item.x += 1
}

move(item: &car) // this works, since it’s now calling the generic function.
assert(car.x == 51) // works

Cheers,
Guillaume Lessard

···

On May 26, 2017, at 00:33, Седых Александр via swift-users <swift-users@swift.org> wrote:


(Zhao Xin) #3

Try this.

protocol Position {

    var x: Double { get set }

}

struct Car: Position {

    var x: Double

}

func move<T>(item: inout T) where T:Position {

    item.x += 1

}

var car = Car(x: 50)

move(item: &car)

car.x // 51

Zhaoxin

···

On Sat, May 27, 2017 at 12:35 AM, Guillaume Lessard via swift-users < swift-users@swift.org> wrote:

In your example, the compiler needs a parameter of type Position. Car is a
type of Position, but they are not interchangeable. See below:

> On May 26, 2017, at 00:33, Седых Александр via swift-users < > swift-users@swift.org> wrote:
>
> protocol Position {
> var x: Double { getset }
> }
>
> struct Car: Position {
> var x: Double
> }
>
> func move(item: inout Position) {
> item.x += 1
> }
>
> var car = Car(x: 50)

var pos: Position = car

move(item: &pos) // this works.
assert(pos.x == 51) // works

The move function as you wrote it requires the memory representation of a
Position variable, which Car does not have; when you assign it to a
Position variable, the Car struct gets accessed through an indirection
layer. (There was a WWDC talk about this last year or the year before.)

You may want a generic function instead:

func move<P: Position>(item: inout P) {
  item.x += 1
}

move(item: &car) // this works, since it’s now calling the generic
function.
assert(car.x == 51) // works

Cheers,
Guillaume Lessard

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


#4

Thanks. Why generic function don not require memory allocate for inout variable, even if it is protocol type?

···

Пятница, 26 мая 2017, 19:35 +03:00 от Guillaume Lessard <glessard@tffenterprises.com>:

In your example, the compiler needs a parameter of type Position. Car is a type of Position, but they are not interchangeable. See below:

On May 26, 2017, at 00:33, Седых Александр via swift-users < swift-users@swift.org > wrote:

protocol Position {
    var x: Double { getset }
}

struct Car: Position {
    var x: Double
}

func move(item: inout Position) {
    item.x += 1
}

var car = Car(x: 50)

var pos: Position = car

move(item: &pos) // this works.
assert(pos.x == 51) // works

The move function as you wrote it requires the memory representation of a Position variable, which Car does not have; when you assign it to a Position variable, the Car struct gets accessed through an indirection layer. (There was a WWDC talk about this last year or the year before.)

You may want a generic function instead:

func move<P: Position>(item: inout P) {
item.x += 1
}

move(item: &car) // this works, since it’s now calling the generic function.
assert(car.x == 51) // works

Cheers,
Guillaume Lessard


(Zhao Xin) #5

Because generic uses `Car` instead of `Position` when running the code, so
there is no casting as `car as Position` as in your original code. The
`T:Position`
part restricts that the type conforms `Position`, but it won't use `Position`,
it uses the type.

Zhaoxin

···

On Sat, May 27, 2017 at 4:58 PM, Седых Александр via swift-users < swift-users@swift.org> wrote:

Thanks. Why generic function don not require memory allocate for inout
variable, even if it is protocol type?

Пятница, 26 мая 2017, 19:35 +03:00 от Guillaume Lessard <
glessard@tffenterprises.com>:

In your example, the compiler needs a parameter of type Position. Car is a
type of Position, but they are not interchangeable. See below:

> On May 26, 2017, at 00:33, Седых Александр via swift-users < > swift-users@swift.org> wrote:
>
> protocol Position {
> var x: Double { getset }
> }
>
> struct Car: Position {
> var x: Double
> }
>
> func move(item: inout Position) {
> item.x += 1
> }
>
> var car = Car(x: 50)

var pos: Position = car

move(item: &pos) // this works.
assert(pos.x == 51) // works

The move function as you wrote it requires the memory representation of a
Position variable, which Car does not have; when you assign it to a
Position variable, the Car struct gets accessed through an indirection
layer. (There was a WWDC talk about this last year or the year before.)

You may want a generic function instead:

func move<P: Position>(item: inout P) {
  item.x += 1
}

move(item: &car) // this works, since it’s now calling the generic
function.
assert(car.x == 51) // works

Cheers,
Guillaume Lessard

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


(Jordan Rose) #6

I think you're missing the underlying semantic problem here:

func transform(item: inout Position) {
  item = Airplane()
}

var car = Car(x: 50)
var pos: Position = car
move(item: &pos) // this works, but 'pos' is now an Airplane
move(item: &car) // this doesn't work because 'car' has to stay a Car

Dave Abrahams likes to phrase this lesson as "generics preserve type information, while protocol values erase it". In this case your Car needs to stay a Car, so you need the type information to be preserved.

Hope that helps,
Jordan

···

On May 27, 2017, at 03:07, Zhao Xin via swift-users <swift-users@swift.org> wrote:

Because generic uses `Car` instead of `Position` when running the code, so there is no casting as `car as Position` as in your original code. The `T:Position` part restricts that the type conforms `Position`, but it won't use `Position`, it uses the type.

Zhaoxin

On Sat, May 27, 2017 at 4:58 PM, Седых Александр via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:
Thanks. Why generic function don not require memory allocate for inout variable, even if it is protocol type?

Пятница, 26 мая 2017, 19:35 +03:00 от Guillaume Lessard <glessard@tffenterprises.com <mailto:glessard@tffenterprises.com>>:

In your example, the compiler needs a parameter of type Position. Car is a type of Position, but they are not interchangeable. See below:

> On May 26, 2017, at 00:33, Седых Александр via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:
>
> protocol Position {
> var x: Double { getset }
> }
>
> struct Car: Position {
> var x: Double
> }
>
> func move(item: inout Position) {
> item.x += 1
> }
>
> var car = Car(x: 50)

var pos: Position = car

move(item: &pos) // this works.
assert(pos.x == 51) // works

The move function as you wrote it requires the memory representation of a Position variable, which Car does not have; when you assign it to a Position variable, the Car struct gets accessed through an indirection layer. (There was a WWDC talk about this last year or the year before.)

You may want a generic function instead:

func move<P: Position>(item: inout P) {
  item.x += 1
}

move(item: &car) // this works, since it’s now calling the generic function.
assert(car.x == 51) // works

Cheers,
Guillaume Lessard

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

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