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

sum for tuples uses + #39182

Closed
bkamins opened this issue Jan 10, 2021 · 2 comments · Fixed by #41510
Closed

sum for tuples uses + #39182

bkamins opened this issue Jan 10, 2021 · 2 comments · Fixed by #41510
Labels
bug Indicates an unexpected problem or unintended behavior maths Mathematical functions stdlib Julia's standard library

Comments

@bkamins
Copy link
Member

bkamins commented Jan 10, 2021

sum for tuples uses + which has the following two consequences:

  1. when a 1-element collection is passed + errors, while standard sum silently accepts the value:
julia> sum(["a"])
"a"
julia> sum(("a",))
ERROR: MethodError: no method matching +(::String)
  1. no promotion happens (as standard sum uses add_sum):
julia> sum([0xe1, 0x1f])
0x0000000000000100
julia> sum((0xe1, 0x1f))
0x00
@NHDaly NHDaly added bug Indicates an unexpected problem or unintended behavior maths Mathematical functions stdlib Julia's standard library labels Jan 23, 2021
@NHDaly
Copy link
Member

NHDaly commented Jan 23, 2021

Just to confirm, indeed the docstring says this is supposed to be promoting to an Int:

 sum(itr)

  Returns the sum of all elements in a collection.

  The return type is Int for signed integers of less than system word size, and UInt for unsigned integers of less than system word size. For all other
  arguments, a common return type is found to which all arguments are promoted.

@NHDaly
Copy link
Member

NHDaly commented Jan 23, 2021

Here's the PR that left this behavior as a TODO:
#22825

It's not clear to me from reading that why this was left unimplemented, whether there are any particular pitfalls or gotchas, or if it was just not finished yet. Does anyone know whether this could just be changed?

NHDaly pushed a commit that referenced this issue Sep 2, 2021
This PR aims to fix #39182 and #39183 by using the universal implementation of `prod` and `sum` from https://github.com/JuliaLang/julia/blob/97f817a379b0c3c5f9bb803427fe88a018ebfe18/base/reduce.jl#L588

However, the file `abstractarray.jl` is included way sooner, and it is crucial to have already a simplified version of `prod` function.

We can specify a simplified version or `prod` only for a system-wide `Int` type that is sufficient to compile `Base`.
``` julia
prod(x::Tuple{}) = 1
# This is consistent with the regular prod because there is no need for size promotion
# if all elements in the tuple are of system size.
prod(x::Tuple{Int, Vararg{Int}}) = *(x...)
```

Although the implementations are different, they lead to the same binary code for tuples containing ~~`UInt` and~~ `Int`.

``` julia
julia> a = (1,2,3)
(1, 2, 3)

# Simplified version for tuples containing Int only
julia> prod_simplified(x::Tuple{Int, Vararg{Int}}) = *(x...)

julia> @code_native prod_simplified(a)
	.text
; ┌ @ REPL[1]:1 within `prod_simplified'
; │┌ @ operators.jl:560 within `*' @ int.jl:88
	movq	8(%rdi), %rax
	imulq	(%rdi), %rax
	imulq	16(%rdi), %rax
; │└
	retq
	nop
; └
```
``` julia
# Regular prod without the simplification
julia> @code_native prod(a)
        .text
; ┌ @ reduce.jl:588 within `prod`
; │┌ @ reduce.jl:588 within `#prod#247`
; ││┌ @ reduce.jl:289 within `mapreduce`
; │││┌ @ reduce.jl:289 within `#mapreduce#240`
; ││││┌ @ reduce.jl:162 within `mapfoldl`
; │││││┌ @ reduce.jl:162 within `#mapfoldl#236`
; ││││││┌ @ reduce.jl:44 within `mapfoldl_impl`
; │││││││┌ @ reduce.jl:48 within `foldl_impl`
; ││││││││┌ @ tuple.jl:276 within `_foldl_impl`
; │││││││││┌ @ operators.jl:613 within `afoldl`
; ││││││││││┌ @ reduce.jl:81 within `BottomRF`
; │││││││││││┌ @ reduce.jl:38 within `mul_prod`
; ││││││││││││┌ @ int.jl:88 within `*`
        movq    8(%rdi), %rax
        imulq   (%rdi), %rax
; │││││││││└└└└
; │││││││││┌ @ operators.jl:614 within `afoldl`
; ││││││││││┌ @ reduce.jl:81 within `BottomRF`
; │││││││││││┌ @ reduce.jl:38 within `mul_prod`
; ││││││││││││┌ @ int.jl:88 within `*`
        imulq   16(%rdi), %rax
; │└└└└└└└└└└└└
        retq
        nop
; └
```
KristofferC pushed a commit that referenced this issue Sep 2, 2021
This PR aims to fix #39182 and #39183 by using the universal implementation of `prod` and `sum` from https://github.com/JuliaLang/julia/blob/97f817a379b0c3c5f9bb803427fe88a018ebfe18/base/reduce.jl#L588

However, the file `abstractarray.jl` is included way sooner, and it is crucial to have already a simplified version of `prod` function.

We can specify a simplified version or `prod` only for a system-wide `Int` type that is sufficient to compile `Base`.
``` julia
prod(x::Tuple{}) = 1
# This is consistent with the regular prod because there is no need for size promotion
# if all elements in the tuple are of system size.
prod(x::Tuple{Int, Vararg{Int}}) = *(x...)
```

Although the implementations are different, they lead to the same binary code for tuples containing ~~`UInt` and~~ `Int`.

``` julia
julia> a = (1,2,3)
(1, 2, 3)

# Simplified version for tuples containing Int only
julia> prod_simplified(x::Tuple{Int, Vararg{Int}}) = *(x...)

julia> @code_native prod_simplified(a)
	.text
; ┌ @ REPL[1]:1 within `prod_simplified'
; │┌ @ operators.jl:560 within `*' @ int.jl:88
	movq	8(%rdi), %rax
	imulq	(%rdi), %rax
	imulq	16(%rdi), %rax
; │└
	retq
	nop
; └
```
``` julia
# Regular prod without the simplification
julia> @code_native prod(a)
        .text
; ┌ @ reduce.jl:588 within `prod`
; │┌ @ reduce.jl:588 within `#prod#247`
; ││┌ @ reduce.jl:289 within `mapreduce`
; │││┌ @ reduce.jl:289 within `#mapreduce#240`
; ││││┌ @ reduce.jl:162 within `mapfoldl`
; │││││┌ @ reduce.jl:162 within `#mapfoldl#236`
; ││││││┌ @ reduce.jl:44 within `mapfoldl_impl`
; │││││││┌ @ reduce.jl:48 within `foldl_impl`
; ││││││││┌ @ tuple.jl:276 within `_foldl_impl`
; │││││││││┌ @ operators.jl:613 within `afoldl`
; ││││││││││┌ @ reduce.jl:81 within `BottomRF`
; │││││││││││┌ @ reduce.jl:38 within `mul_prod`
; ││││││││││││┌ @ int.jl:88 within `*`
        movq    8(%rdi), %rax
        imulq   (%rdi), %rax
; │││││││││└└└└
; │││││││││┌ @ operators.jl:614 within `afoldl`
; ││││││││││┌ @ reduce.jl:81 within `BottomRF`
; │││││││││││┌ @ reduce.jl:38 within `mul_prod`
; ││││││││││││┌ @ int.jl:88 within `*`
        imulq   16(%rdi), %rax
; │└└└└└└└└└└└└
        retq
        nop
; └
```

(cherry picked from commit bada80c)
KristofferC pushed a commit that referenced this issue Sep 3, 2021
This PR aims to fix #39182 and #39183 by using the universal implementation of `prod` and `sum` from https://github.com/JuliaLang/julia/blob/97f817a379b0c3c5f9bb803427fe88a018ebfe18/base/reduce.jl#L588

However, the file `abstractarray.jl` is included way sooner, and it is crucial to have already a simplified version of `prod` function.

We can specify a simplified version or `prod` only for a system-wide `Int` type that is sufficient to compile `Base`.
``` julia
prod(x::Tuple{}) = 1
# This is consistent with the regular prod because there is no need for size promotion
# if all elements in the tuple are of system size.
prod(x::Tuple{Int, Vararg{Int}}) = *(x...)
```

Although the implementations are different, they lead to the same binary code for tuples containing ~~`UInt` and~~ `Int`.

``` julia
julia> a = (1,2,3)
(1, 2, 3)

# Simplified version for tuples containing Int only
julia> prod_simplified(x::Tuple{Int, Vararg{Int}}) = *(x...)

julia> @code_native prod_simplified(a)
	.text
; ┌ @ REPL[1]:1 within `prod_simplified'
; │┌ @ operators.jl:560 within `*' @ int.jl:88
	movq	8(%rdi), %rax
	imulq	(%rdi), %rax
	imulq	16(%rdi), %rax
; │└
	retq
	nop
; └
```
``` julia
# Regular prod without the simplification
julia> @code_native prod(a)
        .text
; ┌ @ reduce.jl:588 within `prod`
; │┌ @ reduce.jl:588 within `#prod#247`
; ││┌ @ reduce.jl:289 within `mapreduce`
; │││┌ @ reduce.jl:289 within `#mapreduce#240`
; ││││┌ @ reduce.jl:162 within `mapfoldl`
; │││││┌ @ reduce.jl:162 within `#mapfoldl#236`
; ││││││┌ @ reduce.jl:44 within `mapfoldl_impl`
; │││││││┌ @ reduce.jl:48 within `foldl_impl`
; ││││││││┌ @ tuple.jl:276 within `_foldl_impl`
; │││││││││┌ @ operators.jl:613 within `afoldl`
; ││││││││││┌ @ reduce.jl:81 within `BottomRF`
; │││││││││││┌ @ reduce.jl:38 within `mul_prod`
; ││││││││││││┌ @ int.jl:88 within `*`
        movq    8(%rdi), %rax
        imulq   (%rdi), %rax
; │││││││││└└└└
; │││││││││┌ @ operators.jl:614 within `afoldl`
; ││││││││││┌ @ reduce.jl:81 within `BottomRF`
; │││││││││││┌ @ reduce.jl:38 within `mul_prod`
; ││││││││││││┌ @ int.jl:88 within `*`
        imulq   16(%rdi), %rax
; │└└└└└└└└└└└└
        retq
        nop
; └
```

(cherry picked from commit bada80c)
KristofferC pushed a commit that referenced this issue Sep 3, 2021
This PR aims to fix #39182 and #39183 by using the universal implementation of `prod` and `sum` from https://github.com/JuliaLang/julia/blob/97f817a379b0c3c5f9bb803427fe88a018ebfe18/base/reduce.jl#L588

However, the file `abstractarray.jl` is included way sooner, and it is crucial to have already a simplified version of `prod` function.

We can specify a simplified version or `prod` only for a system-wide `Int` type that is sufficient to compile `Base`.
``` julia
prod(x::Tuple{}) = 1
# This is consistent with the regular prod because there is no need for size promotion
# if all elements in the tuple are of system size.
prod(x::Tuple{Int, Vararg{Int}}) = *(x...)
```

Although the implementations are different, they lead to the same binary code for tuples containing ~~`UInt` and~~ `Int`.

``` julia
julia> a = (1,2,3)
(1, 2, 3)

# Simplified version for tuples containing Int only
julia> prod_simplified(x::Tuple{Int, Vararg{Int}}) = *(x...)

julia> @code_native prod_simplified(a)
	.text
; ┌ @ REPL[1]:1 within `prod_simplified'
; │┌ @ operators.jl:560 within `*' @ int.jl:88
	movq	8(%rdi), %rax
	imulq	(%rdi), %rax
	imulq	16(%rdi), %rax
; │└
	retq
	nop
; └
```
``` julia
# Regular prod without the simplification
julia> @code_native prod(a)
        .text
; ┌ @ reduce.jl:588 within `prod`
; │┌ @ reduce.jl:588 within `#prod#247`
; ││┌ @ reduce.jl:289 within `mapreduce`
; │││┌ @ reduce.jl:289 within `#mapreduce#240`
; ││││┌ @ reduce.jl:162 within `mapfoldl`
; │││││┌ @ reduce.jl:162 within `#mapfoldl#236`
; ││││││┌ @ reduce.jl:44 within `mapfoldl_impl`
; │││││││┌ @ reduce.jl:48 within `foldl_impl`
; ││││││││┌ @ tuple.jl:276 within `_foldl_impl`
; │││││││││┌ @ operators.jl:613 within `afoldl`
; ││││││││││┌ @ reduce.jl:81 within `BottomRF`
; │││││││││││┌ @ reduce.jl:38 within `mul_prod`
; ││││││││││││┌ @ int.jl:88 within `*`
        movq    8(%rdi), %rax
        imulq   (%rdi), %rax
; │││││││││└└└└
; │││││││││┌ @ operators.jl:614 within `afoldl`
; ││││││││││┌ @ reduce.jl:81 within `BottomRF`
; │││││││││││┌ @ reduce.jl:38 within `mul_prod`
; ││││││││││││┌ @ int.jl:88 within `*`
        imulq   16(%rdi), %rax
; │└└└└└└└└└└└└
        retq
        nop
; └
```

(cherry picked from commit bada80c)
LilithHafner pushed a commit to LilithHafner/julia that referenced this issue Feb 22, 2022
This PR aims to fix JuliaLang#39182 and JuliaLang#39183 by using the universal implementation of `prod` and `sum` from https://github.com/JuliaLang/julia/blob/97f817a379b0c3c5f9bb803427fe88a018ebfe18/base/reduce.jl#L588

However, the file `abstractarray.jl` is included way sooner, and it is crucial to have already a simplified version of `prod` function.

We can specify a simplified version or `prod` only for a system-wide `Int` type that is sufficient to compile `Base`.
``` julia
prod(x::Tuple{}) = 1
# This is consistent with the regular prod because there is no need for size promotion
# if all elements in the tuple are of system size.
prod(x::Tuple{Int, Vararg{Int}}) = *(x...)
```

Although the implementations are different, they lead to the same binary code for tuples containing ~~`UInt` and~~ `Int`.

``` julia
julia> a = (1,2,3)
(1, 2, 3)

# Simplified version for tuples containing Int only
julia> prod_simplified(x::Tuple{Int, Vararg{Int}}) = *(x...)

julia> @code_native prod_simplified(a)
	.text
; ┌ @ REPL[1]:1 within `prod_simplified'
; │┌ @ operators.jl:560 within `*' @ int.jl:88
	movq	8(%rdi), %rax
	imulq	(%rdi), %rax
	imulq	16(%rdi), %rax
; │└
	retq
	nop
; └
```
``` julia
# Regular prod without the simplification
julia> @code_native prod(a)
        .text
; ┌ @ reduce.jl:588 within `prod`
; │┌ @ reduce.jl:588 within `#prod#247`
; ││┌ @ reduce.jl:289 within `mapreduce`
; │││┌ @ reduce.jl:289 within `#mapreduce#240`
; ││││┌ @ reduce.jl:162 within `mapfoldl`
; │││││┌ @ reduce.jl:162 within `#mapfoldl#236`
; ││││││┌ @ reduce.jl:44 within `mapfoldl_impl`
; │││││││┌ @ reduce.jl:48 within `foldl_impl`
; ││││││││┌ @ tuple.jl:276 within `_foldl_impl`
; │││││││││┌ @ operators.jl:613 within `afoldl`
; ││││││││││┌ @ reduce.jl:81 within `BottomRF`
; │││││││││││┌ @ reduce.jl:38 within `mul_prod`
; ││││││││││││┌ @ int.jl:88 within `*`
        movq    8(%rdi), %rax
        imulq   (%rdi), %rax
; │││││││││└└└└
; │││││││││┌ @ operators.jl:614 within `afoldl`
; ││││││││││┌ @ reduce.jl:81 within `BottomRF`
; │││││││││││┌ @ reduce.jl:38 within `mul_prod`
; ││││││││││││┌ @ int.jl:88 within `*`
        imulq   16(%rdi), %rax
; │└└└└└└└└└└└└
        retq
        nop
; └
```
LilithHafner pushed a commit to LilithHafner/julia that referenced this issue Mar 8, 2022
This PR aims to fix JuliaLang#39182 and JuliaLang#39183 by using the universal implementation of `prod` and `sum` from https://github.com/JuliaLang/julia/blob/97f817a379b0c3c5f9bb803427fe88a018ebfe18/base/reduce.jl#L588

However, the file `abstractarray.jl` is included way sooner, and it is crucial to have already a simplified version of `prod` function.

We can specify a simplified version or `prod` only for a system-wide `Int` type that is sufficient to compile `Base`.
``` julia
prod(x::Tuple{}) = 1
# This is consistent with the regular prod because there is no need for size promotion
# if all elements in the tuple are of system size.
prod(x::Tuple{Int, Vararg{Int}}) = *(x...)
```

Although the implementations are different, they lead to the same binary code for tuples containing ~~`UInt` and~~ `Int`.

``` julia
julia> a = (1,2,3)
(1, 2, 3)

# Simplified version for tuples containing Int only
julia> prod_simplified(x::Tuple{Int, Vararg{Int}}) = *(x...)

julia> @code_native prod_simplified(a)
	.text
; ┌ @ REPL[1]:1 within `prod_simplified'
; │┌ @ operators.jl:560 within `*' @ int.jl:88
	movq	8(%rdi), %rax
	imulq	(%rdi), %rax
	imulq	16(%rdi), %rax
; │└
	retq
	nop
; └
```
``` julia
# Regular prod without the simplification
julia> @code_native prod(a)
        .text
; ┌ @ reduce.jl:588 within `prod`
; │┌ @ reduce.jl:588 within `#prod#247`
; ││┌ @ reduce.jl:289 within `mapreduce`
; │││┌ @ reduce.jl:289 within `#mapreduce#240`
; ││││┌ @ reduce.jl:162 within `mapfoldl`
; │││││┌ @ reduce.jl:162 within `#mapfoldl#236`
; ││││││┌ @ reduce.jl:44 within `mapfoldl_impl`
; │││││││┌ @ reduce.jl:48 within `foldl_impl`
; ││││││││┌ @ tuple.jl:276 within `_foldl_impl`
; │││││││││┌ @ operators.jl:613 within `afoldl`
; ││││││││││┌ @ reduce.jl:81 within `BottomRF`
; │││││││││││┌ @ reduce.jl:38 within `mul_prod`
; ││││││││││││┌ @ int.jl:88 within `*`
        movq    8(%rdi), %rax
        imulq   (%rdi), %rax
; │││││││││└└└└
; │││││││││┌ @ operators.jl:614 within `afoldl`
; ││││││││││┌ @ reduce.jl:81 within `BottomRF`
; │││││││││││┌ @ reduce.jl:38 within `mul_prod`
; ││││││││││││┌ @ int.jl:88 within `*`
        imulq   16(%rdi), %rax
; │└└└└└└└└└└└└
        retq
        nop
; └
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Indicates an unexpected problem or unintended behavior maths Mathematical functions stdlib Julia's standard library
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants