# Unexpected broadcasting behavior involving eachrow()

**URL:** <https://discourse.julialang.org/t/unexpected-broadcasting-behavior-involving-eachrow/96781>\
**Category:** General Usage\
**Created:** [March 29, 2023, 1:28pm UTC](https://discourse.julialang.org/t/unexpected-broadcasting-behavior-involving-eachrow/96781 "2023-03-29T13:28:26Z")\
**Posts on this page:** 7\
**Page:** 5

<div class="post-metadata">

**Author:** ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)\
**Post date:** [April 2, 2023, 6:13pm UTC](https://discourse.julialang.org/t/unexpected-broadcasting-behavior-involving-eachrow/96781/83 "2023-04-02T18:13:08Z")

</div>

> [@adienes](#):
>
> Any other place (that I can think of) in Julia where this convention is broken is going to be inside a macro clearly marked by `@` — this is why I would have chosen to have users explicitly opt-in to the behavior with `@fuse` rather than having to opt out.

Macros do not break referential transparency. The _value of the expression_ given to the macro is the code/symbols themselves (not what they would return when executing). So if you have an outer macro that takes the result of an inner macro as its argument, and the inner macro _does return the same string of symbols_ that you could have literally written in the code as an argument, then the outer macro **do give the same result** (i.e., does not break referential transparency). So macros are not inherently breaking referential transparency, they just take their arguments at another time, and so in the phrase _“An expression is called referentially transparent if it can be replaced with its corresponding value (and vice-versa) without changing the program’s behavior.”_ an “expression” must be another macro, and the “value of the expression” is a string of symbols that could have written directly into the code, and yes, those two are interchangeable to the outer macro (i.e., the program will run the same way) if they output the same string of symbols.

> [@adienes](#):
>
> Referential transparency however _is_ certainly a strong convention, and this is broken by automatic loop fusion.

In Julia, the only convention related to “referential transparency” is that the name of methods that mutate their arguments should end with a `!`. And this is not even followed by the IO functions of the standard library (it is assumed that all of them break “referential transparency”). Many languages do not have a strong convention about that, and do not make an effort to distinguish between functions that have referential transparency or not. Because in most languages, breaking referential transparency is exceedingly common, the programmer just needs to write a mutating procedure (which again, outside of functional languages, it is a very typical characteristic of a procedure).

---

<div class="post-metadata">

**Author:** ![adienes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/adienes/32/37459_2.png) [@adienes](https://discourse.julialang.org/u/adienes)\
**Post date:** [April 2, 2023, 7:25pm UTC](https://discourse.julialang.org/t/unexpected-broadcasting-behavior-involving-eachrow/96781/84 "2023-04-02T19:25:06Z")

</div>

Maybe I am not using the term “referential transparency” correctly; I mean to use it in a more human/subjective sense than theoretical. When I say it doesn’t always hold for macros I mean something like how usually if `x = (arg1, arg2, arg3)`, then we can pass in `foo(x...)` just fine, since `x...` can be replaced by its corresponding value, an argument list. On the other hand,

```julia
@evalpoly(1,2,3) # works
@evalpoly(x...) # breaks

```

But since there is that flashing neon `@`, I know to expect non-standard evaluation and don’t mind the lack of “referential transparency,” or whatever term you prefer we use to describe that expectation.

> Because in most languages, breaking referential transparency is exceedingly common

I assume you are referring to functions that modify mutable/global state? I do appreciate very much that Julia has a naming convention that warns users when this happens, but it’s not really what I’m referring to. It might just be my own ignorance, and feel free to correct me, but I don’t think I’ve personally ever used a language that breaks the “transparency” at a syntax level as fundamental as `=` or `()`.

As I’ve been corrected many times above, I know that `.=` is _not_ the same as `=` and in fact should be treated differently; it’s this very distinction I think requires larger hazard signs to be present in the docs, since the symbols just look so similar and behave so similarly in most cases I think it’s a reasonable expectation.

With `=`, I (correctly) expect the following to all leave `var` with the same value

```julia
var = expr
var = (expr)
var = identity(expr)
var = only(Ref(expr))
var = [expr][1]

let tmp = expr
    var = tmp
end

```

The part that appears to break transparency to me is that when using `.=` for `var` and `expr` having equal shapes, suddenly only some of those formulations do what I expect, and the others are broken different.

---

<div class="post-metadata">

**Author:** ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)\
**Post date:** [April 2, 2023, 8:45pm UTC](https://discourse.julialang.org/t/unexpected-broadcasting-behavior-involving-eachrow/96781/85 "2023-04-02T20:45:57Z")

</div>

> [@adienes](#):
>
> It might just be my own ignorance, and feel free to correct me, but I don’t think I’ve personally ever used a language that breaks the “transparency” at a syntax level as fundamental as `=` or `()`.

The problem is: if we do not define “referential transparency” formally, then we cannot discuss if other languages break it or not;

Going again with the technical definition of _“An expression is called referentially transparent if it can be replaced with its corresponding value (and vice-versa) without changing the program’s behavior.”_, then `=` is not referential transparent either, because the _expression_ `x = y` cannot be just replaced by `y` without changing the program (`x` will not change value anymore what changes the semantics of the program). And this is true for basically any language in which `x = y` is an expression, not just an statement.

I am not sure any of these examples you gave have anything to do with referential transparency. Maybe we need a better term to describe whatever implicit rule `.=` is breaking, because for me, it is just the fact you changed one operator for another another completely different, that does not bind a name but takes a mutable object as its first argument and mutate it, and therefore is subject the same aliasing problems any procedure that mutates its arguments have.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [April 2, 2023, 8:55pm UTC](https://discourse.julialang.org/t/unexpected-broadcasting-behavior-involving-eachrow/96781/87 "2023-04-02T20:55:00Z")

</div>

> [@Henrique\_Becker](#):
>
> Going again with the technical definition of _“An expression is called referentially transparent if it can be replaced with its corresponding value (and vice-versa) without changing the program’s behavior.”_, then `=` is not referential transparent either, because the _expression_ `x = y` cannot be just replaced by `y` without changing the program (`x` will not change value anymore what changes the semantics of the program). And this is true for basically any language in which `x = y` is an expression, not just an statement.

You’re right, reassignments are not referentially transparent because the variable’s value is changing so it and expressions involving it cannot be substituted by a value. That’s why some functional languages don’t allow reassignment. adienes was told the term “referential transparency” earlier and that was probably not actually what they meant by `val = mean(x); x = val` being equivalent to `x = mean(x)`.

That just does not imply `val = mean.( (x,) ); x .= val` is equivalent to `x .= mean.( (x,) )`. The desired property _is_ in the latter, just for `=` _per iteration_: `val = mean(x); x[i] = val` is equivalent to `x[i] = mean(x)`. Moreover, `val = mean.( (x,) ); x = val` is equivalent to `x = mean.( (x,) )`. The dotted `.=` is not interchangeable with `=`; a loop of elementwise assignments does not have the same property as 1 variable assignment.

---

<div class="post-metadata">

**Author:** ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)\
**Post date:** [April 2, 2023, 9:00pm UTC](https://discourse.julialang.org/t/unexpected-broadcasting-behavior-involving-eachrow/96781/88 "2023-04-02T21:00:22Z")

</div>

I do not know, maybe this is too simplistic but I think it boils down to:

```julia
julia> [1, 2, 3] .= [4, 5, 6]
3-element Vector{Int64}:
 4
 5
 6

julia> [1, 2, 3] = [4, 5, 6]
ERROR: syntax: invalid assignment location "[1, 2, 3]" around REPL[3]:1
Stacktrace:
 [1] top-level scope
   @ REPL[3]:1

```

`=` is impossible to implement as a method, because it does not take `x` as any value/object bound to that name (which in fact, may not exist yet, the name may be undefined before, we may be declaring it at that point), instead, it takes `x` as a symbol like a macro would.

`.=`, on the other hand, is just a method, and it does not care or even is aware if the first operand (LHS) is a name, a literal, or just any expression that returns a value, it just touches the values of both sides, as any method (and most operators) do.

---

<div class="post-metadata">

**Author:** ![adienes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/adienes/32/37459_2.png) [@adienes](https://discourse.julialang.org/u/adienes)\
**Post date:** [April 3, 2023, 1:38am UTC](https://discourse.julialang.org/t/unexpected-broadcasting-behavior-involving-eachrow/96781/89 "2023-04-03T01:38:08Z")

</div>

> <https://github.com/JuliaLang/julia/pull/49228>
>
> cautionary / explanatory documentation following the wake of https://discourse.j…ulialang.org/t/unexpected-broadcasting-behavior-involving-eachrow/96781/88

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [April 4, 2023, 10:31pm UTC](https://discourse.julialang.org/t/unexpected-broadcasting-behavior-involving-eachrow/96781/90 "2023-04-04T22:31:35Z")

</div>

When broadcasting gets too complicated, I often find it simpler, clearer, and maybe event more performant to just write the for loop. To me white space and structure is clearer than parantheses.

[Previous page](https://discourse.julialang.org/t/unexpected-broadcasting-behavior-involving-eachrow/96781.md?page=4)
