Type inference when assigning the result of reduce to a dictionary


(Martin R) #1

I noticed the following when assigning the result of `reduce()` to a dictionary:

    let array = [1, 2, 3]
    var dict: [Int: Int] = [:]
    dict[0] = array.reduce(0, { $0 + $1 }) // (A)
    // error: binary operator '+' cannot be applied to operands of
type 'Int?' and 'Int'
    // dict[0] = array.reduce(0, { $0 + $1 })
    // ~~ ^ ~~

It seems that the compiler tries to make the RHS an `Int?` and
therefore infers the type of the initial value `0` and the
accumulating value `$0` as `Int?`.

That is in some sense correct, since the dictionary subscript setter
takes an optional as parameter, in this case `Int?`.

However, the code compiles (and runs as expected) if the trailing
closure syntax is used:

    dict[0] = array.reduce(0) { $0 + $1 } // (B)

and also if the initial value is given as `0` instead of `Int(0)`:

    dict[0] = array.reduce(Int(0), { $0 + $1 }) // (C)

My questions are:
- Should (A) compile?
- Why does it make a difference if the trailing closure syntax is used
(A vs. B)?
- Why does it make a difference if the initial value is given as `0`
or `Int(0)` (A vs. C)?

Regards,
Martin


(Joe Groff) #2

No good reason. Got time to file a bug?

-Joe

···

On Oct 4, 2016, at 5:20 AM, Martin R via swift-users <swift-users@swift.org> wrote:

I noticed the following when assigning the result of `reduce()` to a dictionary:

   let array = [1, 2, 3]
   var dict: [Int: Int] = [:]
   dict[0] = array.reduce(0, { $0 + $1 }) // (A)
   // error: binary operator '+' cannot be applied to operands of
type 'Int?' and 'Int'
   // dict[0] = array.reduce(0, { $0 + $1 })
   // ~~ ^ ~~

It seems that the compiler tries to make the RHS an `Int?` and
therefore infers the type of the initial value `0` and the
accumulating value `$0` as `Int?`.

That is in some sense correct, since the dictionary subscript setter
takes an optional as parameter, in this case `Int?`.

However, the code compiles (and runs as expected) if the trailing
closure syntax is used:

   dict[0] = array.reduce(0) { $0 + $1 } // (B)

and also if the initial value is given as `0` instead of `Int(0)`:

   dict[0] = array.reduce(Int(0), { $0 + $1 }) // (C)

My questions are:
- Should (A) compile?
- Why does it make a difference if the trailing closure syntax is used
(A vs. B)?
- Why does it make a difference if the initial value is given as `0`
or `Int(0)` (A vs. C)?


(Martin R) #3

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

···

On 4 Oct 2016, at 21:42, Joe Groff <jgroff@apple.com> wrote:

On Oct 4, 2016, at 5:20 AM, Martin R via swift-users <swift-users@swift.org> wrote:

I noticed the following when assigning the result of `reduce()` to a dictionary:

  let array = [1, 2, 3]
  var dict: [Int: Int] = [:]
  dict[0] = array.reduce(0, { $0 + $1 }) // (A)
  // error: binary operator '+' cannot be applied to operands of
type 'Int?' and 'Int'
  // dict[0] = array.reduce(0, { $0 + $1 })
  // ~~ ^ ~~

It seems that the compiler tries to make the RHS an `Int?` and
therefore infers the type of the initial value `0` and the
accumulating value `$0` as `Int?`.

That is in some sense correct, since the dictionary subscript setter
takes an optional as parameter, in this case `Int?`.

However, the code compiles (and runs as expected) if the trailing
closure syntax is used:

  dict[0] = array.reduce(0) { $0 + $1 } // (B)

and also if the initial value is given as `0` instead of `Int(0)`:

  dict[0] = array.reduce(Int(0), { $0 + $1 }) // (C)

My questions are:
- Should (A) compile?
- Why does it make a difference if the trailing closure syntax is used
(A vs. B)?
- Why does it make a difference if the initial value is given as `0`
or `Int(0)` (A vs. C)?

No good reason. Got time to file a bug?

-Joe


(Joe Groff) #4

Thanks!

-Joe

···

On Oct 4, 2016, at 1:58 PM, Martin R <martinr448@gmail.com> wrote:

On 4 Oct 2016, at 21:42, Joe Groff <jgroff@apple.com> wrote:

On Oct 4, 2016, at 5:20 AM, Martin R via swift-users <swift-users@swift.org> wrote:

I noticed the following when assigning the result of `reduce()` to a dictionary:

let array = [1, 2, 3]
var dict: [Int: Int] = [:]
dict[0] = array.reduce(0, { $0 + $1 }) // (A)
// error: binary operator '+' cannot be applied to operands of
type 'Int?' and 'Int'
// dict[0] = array.reduce(0, { $0 + $1 })
// ~~ ^ ~~

It seems that the compiler tries to make the RHS an `Int?` and
therefore infers the type of the initial value `0` and the
accumulating value `$0` as `Int?`.

That is in some sense correct, since the dictionary subscript setter
takes an optional as parameter, in this case `Int?`.

However, the code compiles (and runs as expected) if the trailing
closure syntax is used:

dict[0] = array.reduce(0) { $0 + $1 } // (B)

and also if the initial value is given as `0` instead of `Int(0)`:

dict[0] = array.reduce(Int(0), { $0 + $1 }) // (C)

My questions are:
- Should (A) compile?
- Why does it make a difference if the trailing closure syntax is used
(A vs. B)?
- Why does it make a difference if the initial value is given as `0`
or `Int(0)` (A vs. C)?

No good reason. Got time to file a bug?

-Joe

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