Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-8148] inout is not working with subclass object throws Cannot pass immutable value #3667

Closed
swift-ci opened this issue Jun 29, 2018 · 4 comments

Comments

@swift-ci
Copy link
Contributor

Previous ID SR-8148
Radar None
Original Reporter prashantkt (JIRA User)
Type Bug
Status Closed
Resolution Done
Environment

Using XCODE 9.3

Swift 4.1

ios 11 +

Additional Detail from JIRA
Votes 0
Component/s CodeCompletion, Foundation
Labels Bug
Assignee None
Priority Medium

md5: 1fcfb7f12ae9da038b4cb352aa28c3bc

duplicates:

  • SR-8155 Improve the error message when using existentials as inout arguments

Issue Description:

I have following code.

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
  // BLOCK 1 Which is not working 
    guard let planeAnchor = anchor as? ARPlaneAnchor else { return }

    var plane = Plane(with: planeAnchor) //IT IS SUBCLASS OF SCNNode
    var geo = plane.geometry
    plane.transform = SCNMatrix4MakeRotation(-.pi / 2, 1, 0, 0)

    update(&plane, withGeometry: plane.geo, type: .static)

   //Up here Cannot pass immutable value as inout argument: implicit conversion from 'Plane' to 'SCNNode' requires a temporary

    node.addChildNode(plane)

   // BLOCK 2 Which is working 


    let width = CGFloat(planeAnchor.extent.x)
    let height = CGFloat(planeAnchor.extent.z)
    let plane1 = SCNPlane(width: width, height: height)

    plane1.materials.first?.diffuse.contents = UIColor.white.withAlphaComponent(0.5)

    var planeNode = SCNNode(geometry: plane1)

    let x = CGFloat(planeAnchor.center.x)
    let y = CGFloat(planeAnchor.center.y)
    let z = CGFloat(planeAnchor.center.z)
    planeNode.position = SCNVector3(x,y,z)
    planeNode.eulerAngles.x = -.pi / 2

    update(&planeNode, withGeometry: plane1, type: .static)
    // WORKING FINE

    node.addChildNode(planeNode)

    self.planes[anchor.identifier] = plane

}

Now Check

 var plane = Plane(with: planeAnchor) 

is a subclass of `SCNNode` when try to pass it in `update` method which has `SCNPhysicsBody` applied to that node

it throws

Cannot pass immutable value as inout argument: implicit conversion from 'Plane' to 'SCNNode' requires a temporary

However for simple object `planeNode` it is not showing any error

@beccadax
Copy link
Contributor

Hi Prashant,

I’m pretty sure Swift is supposed to behave this way. The problem is, `update(_:withGeometry:type🙂` could assign a plain old `SCNNode` to that `inout` parameter, but not all `SCNNode`s can be put into `plane`—only `plane`s can. So Swift rejects this as a type error.

There are three ways you could solve this. The first is to explicitly give `plane` the type `SCNNode`, like this: `var plane: SCNNode = Plane(with: planeAnchor)`. The second is to make the parameter not be `inout`—if you’re just setting properties on the `Plane`, it probably doesn’t need to be `inout`. The other is to change the method from `func update(: inout SCNNode, withGeometry: ...)` to `func update<T: SCNNode>(: inout T, withGeometry: ...)`; that means `update(_withGeometry:type🙂` will only be able to replace `plane` with another `Plane`, not with a different kind of `SCNNode`.

Hope this helps!

@swift-ci
Copy link
Contributor Author

Comment by Prashant Tukadiya (JIRA)

Hi Brent,

Thanks for that explanation

I can't declare it with `var plane: SCNNode` then after I can't use inner properties of that subclass (need to type cast ), Yes I know about pass by reference that you mentioned in your solution so with that I do not need to add inout. But I am playing with inout 😛

I’m pretty sure Swift is supposed to behave this way :- This is strange to me. I was thinking that object is still representing SCNNode class so it should work as inout. But as you mentioned inout required pure types means it not allow subclass to be passed in Please correct me if I am wrong.

Again thanks

@swift-ci
Copy link
Contributor Author

Comment by Prashant Tukadiya (JIRA)

it is default swift behaviour

@beccadax
Copy link
Contributor

It’s not that the value can’t be a subclass, it’s that the variable you put it in must have exactly the same type as the inout parameter.

Another way to address this would be to write something like:

let plane = Plane(…)
// Use the Plane-specific APIs here
var planeNode: SCNNode = plane
update(&planeNode, …)

Maybe the error message could suggest this; Swift is right to diagnose this code as incorrect, that doesn’t mean the error is as helpful as it should be.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
@shahmishal shahmishal transferred this issue from apple/swift May 5, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants