# Why does append!(df1, df2) return a DataFrame, as well as modify the argument df1?

**URL:** <https://discourse.julialang.org/t/why-does-append-df1-df2-return-a-dataframe-as-well-as-modify-the-argument-df1/122329>\
**Category:** New to Julia\
**Tags:** question\
**Created:** [November 6, 2024, 11:03am UTC](https://discourse.julialang.org/t/why-does-append-df1-df2-return-a-dataframe-as-well-as-modify-the-argument-df1/122329 "2024-11-06T11:03:07Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![world-peace](https://avatars.discourse-cdn.com/v4/letter/w/9f8e36/32.png) [@world-peace](https://discourse.julialang.org/u/world-peace)\
**Post date:** [November 6, 2024, 11:03am UTC](https://discourse.julialang.org/t/why-does-append-df1-df2-return-a-dataframe-as-well-as-modify-the-argument-df1/122329/1 "2024-11-06T11:03:07Z")

</div>

It seems like the `append!` function, as defined in the `DataFrames` package both returns a value and modifies the value of one of its arguments.

This seems strange and I am struggling to understand why this happens.

I picked up on this because I had a function which called `append!` just before returning.

```julia
function example(df1, df2)::Nothing
    # some stuff here ...
    append!(df1, df2)
end

```

This function produces an error because it _does not_ return `nothing`. It returns the value returned by `append!`.

---

<div class="post-metadata">

**Author:** ![kevbonham](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kevbonham/32/216165_2.png) [@kevbonham](https://discourse.julialang.org/u/kevbonham)\
**Post date:** [November 6, 2024, 11:55am UTC](https://discourse.julialang.org/t/why-does-append-df1-df2-return-a-dataframe-as-well-as-modify-the-argument-df1/122329/2 "2024-11-06T11:55:44Z")

</div>

> [@world-peace](#):
>
> This seems strange and I am struggling to understand why this happens

I’m guessing that DataFrames is just following the semantics that Base uses - when you `append!` a Vector or something, the modified object is returned as well.

Can you say a bit more about why it seems strange to you?

One solution to your specific issue is that you can add an explicit `return nothing` to the end of your function of you want. But unless you’re often wanting to grab that `nothing`, there’s no harm in leaving the return value as a DataFrame (or just not specifying it)

---

<div class="post-metadata">

**Author:** ![world-peace](https://avatars.discourse-cdn.com/v4/letter/w/9f8e36/32.png) [@world-peace](https://discourse.julialang.org/u/world-peace)\
**Post date:** [November 6, 2024, 12:15pm UTC](https://discourse.julialang.org/t/why-does-append-df1-df2-return-a-dataframe-as-well-as-modify-the-argument-df1/122329/3 "2024-11-06T12:15:25Z")

</div>

Functions usually either modify one of their arguments, or do not modify their arguments and return a new value.

Normally you would expect one of the two semantics:

```julia
isnothing(sort!(df1, df2))
# df1 modified, `nothing` returned

```

or

```julia
df3 = sort(df1, df2)
# neither df1, df2 modified, new value returned

```

This is not a Julia specific thing - it’s just sort of how most languages / APIs work.

---

<div class="post-metadata">

**Author:** ![carstenbauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carstenbauer/32/4981_2.png) [@carstenbauer](https://discourse.julialang.org/u/carstenbauer)\
**Post date:** [November 6, 2024, 12:19pm UTC](https://discourse.julialang.org/t/why-does-append-df1-df2-return-a-dataframe-as-well-as-modify-the-argument-df1/122329/4 "2024-11-06T12:19:43Z")

</div>

The behavior is useful for chaining in-place function calls.

---

<div class="post-metadata">

**Author:** ![mrufsvold](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrufsvold/32/31600_2.png) [@mrufsvold](https://discourse.julialang.org/u/mrufsvold)\
**Post date:** [November 6, 2024, 12:34pm UTC](https://discourse.julialang.org/t/why-does-append-df1-df2-return-a-dataframe-as-well-as-modify-the-argument-df1/122329/5 "2024-11-06T12:34:52Z")

</div>

By returning the modified object, in-place operations can be chained:

```julia
vec = map!(x->x^2, append!(get_vec(), (3,4)))

```

Edit: @carstenbauer beat me to it! Sorry!

---

<div class="post-metadata">

**Author:** ![lupemba](https://avatars.discourse-cdn.com/v4/letter/l/e5b9ba/32.png) [@lupemba](https://discourse.julialang.org/u/lupemba)\
**Post date:** [November 6, 2024, 12:37pm UTC](https://discourse.julialang.org/t/why-does-append-df1-df2-return-a-dataframe-as-well-as-modify-the-argument-df1/122329/6 "2024-11-06T12:37:39Z")

</div>

> [@world-peace](#):
>
> Functions usually either modify one of their arguments, or do not modify their arguments and return a new value.

I am not so sure about this statement. My experience is that the function `pop` normally removes the last element from a list and return it. That is a function that both modify the input and returns a value.

As example is here JavaScript pop and python pop.

> **[W3Schools.com](https://www.w3schools.com/python/ref_list_pop.asp)**
>
> W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.

> **[W3Schools.com](https://www.w3schools.com/jsref/jsref_pop.asp)**
>
> W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.

---

<div class="post-metadata">

**Author:** ![kevbonham](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kevbonham/32/216165_2.png) [@kevbonham](https://discourse.julialang.org/u/kevbonham)\
**Post date:** [November 6, 2024, 12:38pm UTC](https://discourse.julialang.org/t/why-does-append-df1-df2-return-a-dataframe-as-well-as-modify-the-argument-df1/122329/7 "2024-11-06T12:38:36Z")

</div>

> [@world-peace](#):
>
> Normally you would expect

I mean, **I** wouldn’t, but maybe that’s because I’ve been using Julia so long 😅. `sort!` should indeed return the modified value.

I know that one thing that’s different about julia is that _all_ functions return, even if what they return is `nothing`. For example, I think in python you can’t actually do `foo = print("foo")` (though it’s been a long time, I confess I don’t remember).

I think the chaining above is a nice side effect, but I don’t know if that’s the motivation. For me, working in the repl, it’s a nice feature that I see the outcome of my operations. Also, AFIACT, there’s no downside to returning the value, so why not do it?

---

<div class="post-metadata">

**Author:** ![kevbonham](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kevbonham/32/216165_2.png) [@kevbonham](https://discourse.julialang.org/u/kevbonham)\
**Post date:** [November 6, 2024, 12:44pm UTC](https://discourse.julialang.org/t/why-does-append-df1-df2-return-a-dataframe-as-well-as-modify-the-argument-df1/122329/8 "2024-11-06T12:44:48Z")

</div>

> [@kevbonham](#):
>
> For example, I think in python you can’t actually

This is wrong, you can and it’s `None`.

---

<div class="post-metadata">

**Author:** ![DanielVandH](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielvandh/32/31134_2.png) [@DanielVandH](https://discourse.julialang.org/u/DanielVandH)\
**Post date:** [November 6, 2024, 12:47pm UTC](https://discourse.julialang.org/t/why-does-append-df1-df2-return-a-dataframe-as-well-as-modify-the-argument-df1/122329/9 "2024-11-06T12:47:17Z")

</div>

This behaviour is also documented in the docstring for `append!`

```julia
help?> append!
search: append! prepend! swapfield!

  append!(collection, collections...) -> collection.

  For an ordered container collection, add the elements of each collections to the end of it.

  │ Julia 1.6
  │
  │ Specifying multiple collections to be appended requires at least Julia 1.6.

```

It’s expected to return the collection. As does e.g. `push!`. This extra return doesn’t give you any extra allocations or anything either so, it doesn’t cause you any performance problems if you don’t want to make use of it.

---

<div class="post-metadata">

**Author:** ![world-peace](https://avatars.discourse-cdn.com/v4/letter/w/9f8e36/32.png) [@world-peace](https://discourse.julialang.org/u/world-peace)\
**Post date:** [November 6, 2024, 1:09pm UTC](https://discourse.julialang.org/t/why-does-append-df1-df2-return-a-dataframe-as-well-as-modify-the-argument-df1/122329/10 "2024-11-06T13:09:53Z")

</div>

> [@carstenbauer](#):
>
> The behavior is useful for chaining in-place function calls.

> [@mrufsvold](#):
>
> By returning the modified object, in-place operations can be chained:
> 
> ```julia
> vec = map!(x->x^2, append!(get_vec(), (3,4)))
> 
> ```
> 
> Edit: @carstenbauer beat me to it! Sorry!

A fair point. It’s a shame there wasn’t a second function introduced for this purpose however. (Probably with a different name?)

It could have been `append` and `append!`, possibly.

> [@lupemba](#):
>
> I am not so sure about this statement. My experience is that the function `pop` normally removes the last element from a list and return it. That is a function that both modify the input and returns a value.

This isn’t the same situation. If `pop!` returned the input, you would say it was strange. It is normal for a function to take some inputs and return some different thing. What is weird is for a function to take some inputs and return those _same_ things.

For example, the equivalent behaviour in this case would be for `pop!` to return _not just the removed element but also the input container itself, presumably as a tuple or a pair_. If this was how it worked, it would be strange.

---

<div class="post-metadata">

**Author:** ![DanielVandH](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielvandh/32/31134_2.png) [@DanielVandH](https://discourse.julialang.org/u/DanielVandH)\
**Post date:** [November 6, 2024, 1:18pm UTC](https://discourse.julialang.org/t/why-does-append-df1-df2-return-a-dataframe-as-well-as-modify-the-argument-df1/122329/11 "2024-11-06T13:18:12Z")

</div>

> [@world-peace](#):
>
> It could have been `append` and `append!`, possibly.

But then you’re having to allocate into a new collection. The point is to reuse the same collection and then pass it into another function.

---

<div class="post-metadata">

**Author:** ![Wispy](https://avatars.discourse-cdn.com/v4/letter/w/a587f6/32.png) [@Wispy](https://discourse.julialang.org/u/Wispy)\
**Post date:** [November 6, 2024, 1:34pm UTC](https://discourse.julialang.org/t/why-does-append-df1-df2-return-a-dataframe-as-well-as-modify-the-argument-df1/122329/12 "2024-11-06T13:34:17Z")

</div>

Relevant discussion from Martin Fowler: [Command Query Separation](https://martinfowler.com/bliki/CommandQuerySeparation.html)

---

<div class="post-metadata">

**Author:** ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)\
**Post date:** [November 6, 2024, 2:01pm UTC](https://discourse.julialang.org/t/why-does-append-df1-df2-return-a-dataframe-as-well-as-modify-the-argument-df1/122329/13 "2024-11-06T14:01:39Z")

</div>

> [@lupemba](#):
>
> I am not so sure about this statement. My experience is that the function `pop` normally removes the last element from a list and return it. That is a function that both modify the input and returns a value.

The original statement is a common pattern in OOP, it is stated as one of the design principles, e.g. in “A Touch of class” by Bertrand Meyer, with `pop` mentioned as the only notable exception from the rule. The principles itself goes back probably to Algol, which was one of (if not the) first languages to distinguish subprograms into procedures which modify data and functions which return values.

That said, Julia is expression-based language. That means, any syntactically valid code unit has a value (can be used as rhp of an assignment expression). E.g., an expression `x = for i in 1:10; s+=i; end` is valid and `x = nothing` after evaluation, provided a variable `s` exists in the evaluation scope. This is why any subprogram, even those considered as procedures in statement-based languages, returns a value. Returning the modified argument for `sort!`, `append!`, `push!`, `reverse!` etc. is actually convenient for chaining operations, folds, and for immediate display of the action in REPL, as others have noticed.

---

<div class="post-metadata">

**Author:** ![world-peace](https://avatars.discourse-cdn.com/v4/letter/w/9f8e36/32.png) [@world-peace](https://discourse.julialang.org/u/world-peace)\
**Post date:** [November 6, 2024, 3:25pm UTC](https://discourse.julialang.org/t/why-does-append-df1-df2-return-a-dataframe-as-well-as-modify-the-argument-df1/122329/14 "2024-11-06T15:25:09Z")

</div>

Ok fine - you have convinced me.

I would say there should be _three_ functions for the different usecases but I don’t genuinely believe that on balance that is a better solution. It would require creating a new name for a function just to do this - unless someone were to introduce a symbol like `!` which could be used to disambiguate two functions with the same “name”.

---

<div class="post-metadata">

**Author:** ![kevbonham](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kevbonham/32/216165_2.png) [@kevbonham](https://discourse.julialang.org/u/kevbonham)\
**Post date:** [November 6, 2024, 3:48pm UTC](https://discourse.julialang.org/t/why-does-append-df1-df2-return-a-dataframe-as-well-as-modify-the-argument-df1/122329/15 "2024-11-06T15:48:34Z")

</div>

> [@world-peace](#):
>
> I would say there should be _three_ functions for the different usecases

I suppose I’m confused about what the different use cases are. As in, what’s the advantage of having a version that returns `nothing`, since

> [@DanielVandH](#):
>
> This extra return doesn’t give you any extra allocations or anything either so, it doesn’t cause you any performance problems if you don’t want to make use of it.

?

If you don’t want the return value, just don’t (re)assign it. If you want your original function to return `nothing`, then just write `return nothing` at the end. It would seem odd to me to have multiple functions with the same purpose, except that one returns `nothing`.

As an aside, some Julia style guides (and my own preference) suggest explicit returns, so even if you wanted your function to return the dataframe, I would write it as

```julia
    ...
    append!(df1, df2)
    return df1
end

```

---

<div class="post-metadata">

**Author:** ![world-peace](https://avatars.discourse-cdn.com/v4/letter/w/9f8e36/32.png) [@world-peace](https://discourse.julialang.org/u/world-peace)\
**Post date:** [November 6, 2024, 5:15pm UTC](https://discourse.julialang.org/t/why-does-append-df1-df2-return-a-dataframe-as-well-as-modify-the-argument-df1/122329/16 "2024-11-06T17:15:27Z")

</div>

> [@kevbonham](#):
>
> As in, what’s the advantage of having a version that returns `nothing`

It fixes this bug

```julia
function some()::Nothing
    append!(...,...) # does not return `nothing`
end

```

---

<div class="post-metadata">

**Author:** ![carstenbauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carstenbauer/32/4981_2.png) [@carstenbauer](https://discourse.julialang.org/u/carstenbauer)\
**Post date:** [November 6, 2024, 5:27pm UTC](https://discourse.julialang.org/t/why-does-append-df1-df2-return-a-dataframe-as-well-as-modify-the-argument-df1/122329/17 "2024-11-06T17:27:13Z")

</div>

That’s not a bug but a misconception of how Julia works (i.e. its conventions).

Btw, I quite generally recommend explicit return statements in which case this “issue” wouldn’t occur in the first place.

---

<div class="post-metadata">

**Author:** ![DanielVandH](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielvandh/32/31134_2.png) [@DanielVandH](https://discourse.julialang.org/u/DanielVandH)\
**Post date:** [November 6, 2024, 6:00pm UTC](https://discourse.julialang.org/t/why-does-append-df1-df2-return-a-dataframe-as-well-as-modify-the-argument-df1/122329/18 "2024-11-06T18:00:44Z")

</div>

Functions return the last value if there is no explicit `return`. Just add a `return nothing` if you really think it’s important to return `nothing`

---

<div class="post-metadata">

**Author:** ![kevbonham](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kevbonham/32/216165_2.png) [@kevbonham](https://discourse.julialang.org/u/kevbonham)\
**Post date:** [November 6, 2024, 6:39pm UTC](https://discourse.julialang.org/t/why-does-append-df1-df2-return-a-dataframe-as-well-as-modify-the-argument-df1/122329/19 "2024-11-06T18:39:58Z")

</div>

> [@world-peace](#):
>
> It fixes this bug

It’s not a bug (as mentioned), but you can “fix” it anyway with

```julia
function some()
    append!(...,...) # does not return `nothing`
end

# or

function some()::Nothing
    append!(...,...) # does not return `nothing`
    return nothing
end

# or even 

function some()::Nothing
    append!(...,...) # does not return `nothing`
    nothing
end

# or finally

function nappend!(args...)
    append!(args...)
    return nothing
end

function some()::Nothing
    nappend!(...,...) 
end

```

---

<div class="post-metadata">

**Author:** ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)\
**Post date:** [November 6, 2024, 8:04pm UTC](https://discourse.julialang.org/t/why-does-append-df1-df2-return-a-dataframe-as-well-as-modify-the-argument-df1/122329/20 "2024-11-06T20:04:23Z")

</div>

I really don’t like functions which return nothing, especially if there is a meaningful value that could be returned instead. Here is an example in Java:

```java
Map<String,Integer> h = new HashMap<String,Integer>();
h.put("a", 1);
h.put("b", 2);

```

This would be much nicer, if I could chain method calls `h.put("a", 1).put("b", 2)` instead, and fortunately [fluent interfaces](https://en.wikipedia.org/wiki/Fluent_interface) are becoming more popular in the OOP world as well. In the meantime, also some macros – such as Clojure’s [doto](https://clojuredocs.org/clojure.core/doto) – go a long way in providing nicer chaining syntax.

[Next page](https://discourse.julialang.org/t/why-does-append-df1-df2-return-a-dataframe-as-well-as-modify-the-argument-df1/122329.md?page=2)
