Lazy expression is ambiguous?


(Rick M) #1

I get this error in the following code: "Type of expression is ambiguous without more context", on the DispatchQueue. But only if I mark it as "lazy", and not if I don't. I'm not sure why.

class
myClass
{
  lazy var myQ = DispatchQueue(label: "Op", attributes: .concurrent) // <-- ERROR
                 ^Type of expression is ambiguous without more context
}

Would someone please explain? Thank you.

···

--
Rick Mann
rmann@latencyzero.com


(Jacob Bandes-Storch) #2

This problem seems to occur when using an initializer with some default
argument values. The following code also exhibits the issue:

struct Bar {
  init(x: Int, y: Int? = 42) { }
}

class Foo {
  lazy var myQ = Bar(x: 3)
}

I'd recommend filing a bug at bugs.swift.org.

···

On Sun, Sep 11, 2016 at 10:19 PM, Rick Mann via swift-users < swift-users@swift.org> wrote:

I get this error in the following code: "Type of expression is ambiguous
without more context", on the DispatchQueue. But only if I mark it as
"lazy", and not if I don't. I'm not sure why.

class
myClass
{
  lazy var myQ = DispatchQueue(label: "Op", attributes: .concurrent) //
<-- ERROR
                 ^Type of expression is ambiguous without more context
}

Would someone please explain? Thank you.

--
Rick Mann
rmann@latencyzero.com

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


(Rick M) #3

Done. https://bugs.swift.org/browse/SR-2616

···

On Sep 11, 2016, at 22:40 , Jacob Bandes-Storch <jtbandes@gmail.com> wrote:

This problem seems to occur when using an initializer with some default argument values. The following code also exhibits the issue:

struct Bar {
  init(x: Int, y: Int? = 42) { }
}

class Foo {
  lazy var myQ = Bar(x: 3)
}

I'd recommend filing a bug at bugs.swift.org.

On Sun, Sep 11, 2016 at 10:19 PM, Rick Mann via swift-users <swift-users@swift.org> wrote:
I get this error in the following code: "Type of expression is ambiguous without more context", on the DispatchQueue. But only if I mark it as "lazy", and not if I don't. I'm not sure why.

class
myClass
{
  lazy var myQ = DispatchQueue(label: "Op", attributes: .concurrent) // <-- ERROR
                 ^Type of expression is ambiguous without more context
}

Would someone please explain? Thank you.

--
Rick Mann
rmann@latencyzero.com

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

--
Rick Mann
rmann@latencyzero.com


(Quinn “The Eskimo!”) #4

Agreed.

Also, you can work around this by adding a type.

  lazy var myQ: DispatchQueue = DispatchQueue(label: "Op", attributes: .concurrent)

Also, with regards this specific example, be aware that lazy properties aren’t guaranteed to be initialised only once. To quote “The Swift Programming Language”:

    If a property marked with the `lazy` modified is accessed by multiple
    threads simultaneously and the property has not yet been initialized,
    there is no guarantee that the property will be initialized only once.

I’m struggling to think of a case where that limitation is acceptable in the context of a dispatch queue (-:

Share and Enjoy

···

On 12 Sep 2016, at 06:40, Jacob Bandes-Storch via swift-users <swift-users@swift.org> wrote:

I'd recommend filing a bug at bugs.swift.org.

--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware


(Rick M) #5

I'd recommend filing a bug at bugs.swift.org.

Agreed.

Done. https://bugs.swift.org/browse/SR-2616

Also, you can work around this by adding a type.

lazy var myQ: DispatchQueue = DispatchQueue(label: "Op", attributes: .concurrent)

Sure, it just didn't seem to make sense.

Also, with regards this specific example, be aware that lazy properties aren’t guaranteed to be initialised only once. To quote “The Swift Programming Language”:

   If a property marked with the `lazy` modified is accessed by multiple
   threads simultaneously and the property has not yet been initialized,
   there is no guarantee that the property will be initialized only once.

I’m struggling to think of a case where that limitation is acceptable in the context of a dispatch queue (-:

Thank you for that explanation. I had assumed lazy worked like static, which I understand uses dispatch_once under the hood. Would that be a reasonable thing for lazy to do?

In the end I didn't use a property for the queue, but rather just created it at point of use (I'm testing to see whether or not the enqueued blocks retain the queue; that's all I need).

···

On Sep 12, 2016, at 00:02 , Quinn The Eskimo! via swift-users <swift-users@swift.org> wrote:
On 12 Sep 2016, at 06:40, Jacob Bandes-Storch via swift-users <swift-users@swift.org> wrote:

--
Rick Mann
rmann@latencyzero.com


(Quinn “The Eskimo!”) #6

I had assumed lazy worked like static, which I understand uses dispatch_once under the hood.

Correct.

[I’m not sure if it actually /uses/ `dispatch_once` specifically, but it has the same semantics.]

Would that be a reasonable thing for lazy to do?

It certainly would be nice. I suspect that this would be hard to implement because the restrictions associated with `dispatch_once` are pretty tight. OTOH, if you’d like to see it work this way it wouldn’t hurt to file an enhancement request.

Share and Enjoy

···

On 12 Sep 2016, at 08:46, Rick Mann <rmann@latencyzero.com> wrote:
--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware


(Zhao Xin) #7

It is not a bug. You must explicitly specify the variable's type if you use
`lazy` keyword. `lazy` means the variable will be initialized later, but
the compiler needs its type right now.

Zhaoxin

···

On Mon, Sep 12, 2016 at 3:02 PM, Quinn "The Eskimo!" via swift-users < swift-users@swift.org> wrote:

On 12 Sep 2016, at 06:40, Jacob Bandes-Storch via swift-users < > swift-users@swift.org> wrote:

> I'd recommend filing a bug at bugs.swift.org.

Agreed.

Also, you can work around this by adding a type.

  lazy var myQ: DispatchQueue = DispatchQueue(label: "Op", attributes:
.concurrent)

Also, with regards this specific example, be aware that lazy properties
aren’t guaranteed to be initialised only once. To quote “The Swift
Programming Language”:

    If a property marked with the `lazy` modified is accessed by multiple
    threads simultaneously and the property has not yet been initialized,
    there is no guarantee that the property will be initialized only once.

I’m struggling to think of a case where that limitation is acceptable in
the context of a dispatch queue (-:

Share and Enjoy
--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

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


(Rick M) #8

I had assumed lazy worked like static, which I understand uses dispatch_once under the hood.

Correct.

[I’m not sure if it actually /uses/ `dispatch_once` specifically, but it has the same semantics.]

Would that be a reasonable thing for lazy to do?

It certainly would be nice. I suspect that this would be hard to implement because the restrictions associated with `dispatch_once` are pretty tight. OTOH, if you’d like to see it work this way it wouldn’t hurt to file an enhancement request.

Oh, right, because it seems to need a static or global variable for the flag. I've always wondered why that was the case. Seems like any flag would do (like a member variable), and if that results in a second dispatch because it's a second flag, that's okay.

In any case, thanks for all the clarification.

···

On Sep 12, 2016, at 00:53 , Quinn The Eskimo! via swift-users <swift-users@swift.org> wrote:
On 12 Sep 2016, at 08:46, Rick Mann <rmann@latencyzero.com> wrote:

Share and Enjoy
--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

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

--
Rick Mann
rmann@latencyzero.com


(Quinn “The Eskimo!”) #9

It is not a bug.

I disagree.

You must explicitly specify the variable's type if you use `lazy` keyword.

No, that’s not the case in general. For example, the following code compiles just fine.

  import Dispatch

  func queueMaker() -> DispatchQueue {
    return DispatchQueue(label: "Op", attributes: .concurrent)
  }

  class MyClass {
    lazy var myQ = queueMaker()
  }

Regardless, there’s two possibilities here:

A. this is a real restriction in the language, which makes the poor diagnostic bugworthy

B. this is a false restriction, which makes it bugworthy in and of itself

While I personally believe that B is the case here, that’s really besides the point; something, either A or B, should change, and hence my advice.

Share and Enjoy

···

On 12 Sep 2016, at 08:28, Zhao Xin <owenzx@gmail.com> wrote:
--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware


(Quinn “The Eskimo!”) #10

I had assumed lazy worked like static, which I understand uses dispatch_once under the hood.

Correct.

Re-reading the above I realise that it was ambiguous. Let’s try that again.

                   * * *

I had assumed lazy worked like static …

No, alas.

which I understand uses dispatch_once under the hood.

Your understanding of `static` is correct.

Share and Enjoy

···

On 12 Sep 2016, at 08:53, Quinn The Eskimo! via swift-users <swift-users@swift.org> wrote:

On 12 Sep 2016, at 08:46, Rick Mann <rmann@latencyzero.com> wrote:

On 12 Sep 2016, at 08:46, Rick Mann <rmann@latencyzero.com> wrote:
--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware


(Quinn “The Eskimo!”) #11

Implementing `dispatch_once` so that it’s fast on all CPU architectures, including those with a weak memory model, requires that ‘once token’:

* be initialised to 0 before `dispatch_once` sees it

* not modified by anything other than `dispatch_once`

That’s true for [switching to Obj-C terminology here] global variables, which are initialised by the linker to 0 before any instruction in the process runs, but it’s not true for ivars.

If you want to see how this really works, you can check out the source in Darwin.

<http://opensource.apple.com/source/libdispatch/libdispatch-500.1.5/src/once.c>

Frankly, it hurts my brain )-:

Share and Enjoy

···

On 12 Sep 2016, at 09:20, Rick Mann <rmann@latencyzero.com> wrote:

I've always wondered why that was the case.

--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware


(Rick M) #12

Wheeeee!

···

On Sep 12, 2016, at 03:02 , Quinn The Eskimo! via swift-users <swift-users@swift.org> wrote:

On 12 Sep 2016, at 09:20, Rick Mann <rmann@latencyzero.com> wrote:

I've always wondered why that was the case.

Implementing `dispatch_once` so that it’s fast on all CPU architectures, including those with a weak memory model, requires that ‘once token’:

* be initialised to 0 before `dispatch_once` sees it

* not modified by anything other than `dispatch_once`

That’s true for [switching to Obj-C terminology here] global variables, which are initialised by the linker to 0 before any instruction in the process runs, but it’s not true for ivars.

If you want to see how this really works, you can check out the source in Darwin.

<http://opensource.apple.com/source/libdispatch/libdispatch-500.1.5/src/once.c>

Frankly, it hurts my brain )-:

--
Rick Mann
rmann@latencyzero.com