# Unifying unwrapping single-value wrappers

**URL:** https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003
**Category:** Internals & Design
**Tags:** question
**Created:** [October 16, 2023, 9:11am UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003 "2023-10-16T09:11:42Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![schlichtanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/schlichtanders/32/32145_2.png) [@schlichtanders](https://discourse.julialang.org/u/schlichtanders)
#### Post date: [October 16, 2023, 9:11am UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/1 "2023-10-16T09:11:42Z")

</div>

I am stumbling upon that there does not exist a unified method to unwrap a singleton container. This is a feature often wanted, but Julia misses this so far. Some types don’t even have a single unwrapper.

I want to suggest to support `get` as the standard unwrap method.

## Standard Base types I know of which fall into this confusing category:

- `Ref` has `getindex` as unwrap, but does not support get
- `Some` doesn’t have any unwrap method as far as I know (EDIT: as commented, `something` unwraps it)
- `Val` doesn’t have any unwrap method - there is even an issue for it [API request: a function to unwrap Val · Issue #34758 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/34758)
- EDIT: `WeakRef` was mentioned in the comments - it apparently does not have an unwrap method
- … are there others?

## Options for unwrap method

- `get` - would be my personal favourite
- `getindex` - currently used for `Ref`, but not for `Some`, and on the `Val` site there was the comment that it could confuse people that `Val(1)[]` would work, but `Val{1}[]` not (because of visual similarity of the syntax and semantic similarity of Val(1) and Val{1})
- EDIT: `only` was mentioned in a comment - this unwraps Ref already, as well as Vectors with a single element. Fits very very good to the general idea, and is already established.
- another new method like e.g. `unwrap` - would introduce a new API obviously. EDIT: a name commonly used for this concept is `extract` as commented below.

Because of the mentioned reasons I would argue that we should add `get` definitions to all the singleton types like `Ref`, `Some` and `Val` and regard `get` as a standard API for unwrapping singleton wrappers.

What are your thoughts?

> Personal Note: I am also fine with adding both `get` and `getindex` - the confusion argument is not really crucial from my view, as people who are using `Val` are anyway already more advanced in their Julia usage and will know about the pitfalls when confusing Val{1} with Val(1).

---

<div class="post-metadata">

### Author: ![barucden](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/barucden/32/26154_2.png) [@barucden](https://discourse.julialang.org/u/barucden)
#### Post date: [October 16, 2023, 9:15am UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/2 "2023-10-16T09:15:19Z")

</div>

We have `something` that unwraps a `Some`. Although it is more general:

> Return the first value in the arguments which is not equal to nothing, if any.

---

<div class="post-metadata">

### Author: ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)
#### Post date: [October 16, 2023, 3:21pm UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/3 "2023-10-16T15:21:12Z")

</div>

We could make get default to doing a getindex with no args. We can even do the reverse too although I don’t love having circular defaults.

---

<div class="post-metadata">

### Author: ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)
#### Post date: [October 16, 2023, 3:33pm UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/4 "2023-10-16T15:33:55Z")

</div>

`get` is currently always associated with a key & a default; this explicitly requires no key, and theres’s no mention of a default, so I’m inclined to think this concept is a bit different to `get`.

---

<div class="post-metadata">

### Author: ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)
#### Post date: [October 16, 2023, 3:35pm UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/5 "2023-10-16T15:35:17Z")

</div>

There’s a somewhat parallel discussion here: [Single-argument `getindex` only works for some types · Issue #51712 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/51712)

---

<div class="post-metadata">

### Author: ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)
#### Post date: [October 16, 2023, 4:02pm UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/6 "2023-10-16T16:02:47Z")

</div>

After quite a bit of searching, I think what you’re describing is that you want a consistent function to make things a comonad: [Control.Comonad](https://hackage.haskell.org/package/comonad-5.0.8/docs/Control-Comonad.html)

Which would be `extract` (and it’s wrapping counterpart, `extend`).

---

<div class="post-metadata">

### Author: ![schlichtanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/schlichtanders/32/32145_2.png) [@schlichtanders](https://discourse.julialang.org/u/schlichtanders)
#### Post date: [October 16, 2023, 4:40pm UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/7 "2023-10-16T16:40:32Z")

</div>

I like to follow functional standard namings. And as there is so many opinions with the other names, maybe it is really the easiest and most straighforward.

I like to add `extract` as new API to julia which is intended to have co-monad like semantics.

---

<div class="post-metadata">

### Author: ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)
#### Post date: [October 16, 2023, 4:44pm UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/8 "2023-10-16T16:44:44Z")

</div>

But what does unwrapping really _mean_? `Some` is intentionally special with its `something`. You shouldn’t “generically” unwrap a `Some` — it’s entire reason-for-being is to tell you that it’s not nothing.

---

<div class="post-metadata">

### Author: ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)
#### Post date: [October 16, 2023, 5:39pm UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/9 "2023-10-16T17:39:32Z")

</div>

> [@mbauman](#):
>
> But what does unwrapping really _mean_?

Indeed! For example, should the proposed function also unwrap array wrappers, ie do `parent(x)` for abstractarrays?

---

<div class="post-metadata">

### Author: ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)
#### Post date: [October 16, 2023, 5:56pm UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/10 "2023-10-16T17:56:39Z")

</div>

At the moment, unfortunately, `something(x::Any) = x`. It really should error, though.

---

<div class="post-metadata">

### Author: ![schlichtanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/schlichtanders/32/32145_2.png) [@schlichtanders](https://discourse.julialang.org/u/schlichtanders)
#### Post date: [October 17, 2023, 6:39am UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/11 "2023-10-17T06:39:55Z")

</div>

> [@mbauman](#):
>
> But what does unwrapping really _mean_?

the answer was already given by @Sukera

> [@Sukera](#):
>
> After quite a bit of searching, I think what you’re describing is that you want a consistent function to make things a comonad: [Control.Comonad](https://hackage.haskell.org/package/comonad-5.0.8/docs/Control-Comonad.html)
> 
> Which would be `extract` (and it’s wrapping counterpart, `extend`).

I guess this is about the most meaning you can get - supporting the `extract` part of a comonad. That is the technical meaning of course.

The intuitive meaning is luckily also captured in the name `extract` and its type `MyFunctor{T} -> T`, namely that there is a way to extract one element from the given instance of `MyFunctor`.

* * *

If people don’t like these abstractions, they of course can define their own definitions similar to extract, or use more individual methods which better capture the specific meaning of what extract would mean for their context. `something` is not a good example I guess - because it has more features than a simple unwrap. A maybe better example is `fetch`, where almost everyone will prefer using `fetch` instead of `extract`.

---

<div class="post-metadata">

### Author: ![schlichtanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/schlichtanders/32/32145_2.png) [@schlichtanders](https://discourse.julialang.org/u/schlichtanders)
#### Post date: [October 17, 2023, 6:45am UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/12 "2023-10-17T06:45:52Z")

</div>

I like this as well - `get` is for me the most intuitive name in julia for the comonadic `extract`.

Making it default to getindex with no args unifies these intuitions (as for Ref getindex is already defined).  
I wouldn’t do the reverse probably, because indexing syntax is slightly less self-explaining as `get` and hence rather a candidate for explicit definition.

Of course, in addition, this would require definitions for either `get` or `getindex` for `Some` and `Val` to accomplish my final goal.

---

<div class="post-metadata">

### Author: ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)
#### Post date: [October 17, 2023, 7:29am UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/13 "2023-10-17T07:29:48Z")

</div>

I want to note that you really don’t want to ever just “unwrap” a `Some` without knowing that you’re unwrapping a `Some`. You almost always want to take the value out, transform it, and then put it back into a `Some` (or return a `Nothing`). Additionally, you _can’t_ unwrap a `Nothing` - which is the important part of the `Some`/`Nothing` duality, and which must be handled by code expecting a `Some`. In haskell that is enforced by requiring you to fulfill the types - and Julia doesn’t enforce things to that degree (unfortunately).

This is at odds with having a standard “unwrap” (and here I agree with @mbauman), because the fact of having received a `Some` (and not some other comonad) is a meaningful distinction. It’s wrong to think of `Some` as just another single object container, so I think the goal of unifying the interface there (while conceptually/mathematically feasible) is questionable at best.

All of this combined - doubling the meaning of `get` like this seems like a very bad idea to me.

---

<div class="post-metadata">

### Author: ![schlichtanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/schlichtanders/32/32145_2.png) [@schlichtanders](https://discourse.julialang.org/u/schlichtanders)
#### Post date: [October 17, 2023, 8:00am UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/14 "2023-10-17T08:00:35Z")

</div>

While julia does not enforce the types no one stops you from using comonad methods in a safe way.

I agree that the combination of Some/Nothing is not very appropriate for monadic programming, please check out my packages [GitHub - JuliaFunctional/DataTypesBasic.jl: Option, Try, Either, and some more common basic DataTypes](https://github.com/JuliaFunctional/DataTypesBasic.jl) (and [GitHub - JuliaFunctional/TypeClasses.jl: Monoid, Functor, Applicative, Monad and more](https://github.com/JuliaFunctional/TypeClasses.jl)) which fill this need.

As with every method/api which you are using, you of course should think about whether it makes sense. I don’t see anything special here about `extract`. Almost every julia method is generic, so you should better make sure that the method makes sense for your types.

Hence I cannot follow the two of you @Sukera and @mbauman - the meaning is enough well defined so that this api is useful for people (extracting a single canonical value from a wrapper). Same as other methods which are enough well defined to be generic apis (like map, fetch, etc.).

Concretely I cannot imagine a single Julia user who does not understand what `extract(Some(1))` or `extract(Ref(1))` or `extract(Val(1))` would be doing if they see its documentation is saying `extract a single canonical value from a wrapper`.

---

<div class="post-metadata">

### Author: ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)
#### Post date: [October 17, 2023, 10:17am UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/15 "2023-10-17T10:17:01Z")

</div>

> [@schlichtanders](#):
>
> Concretely I cannot imagine a single Julia user who does not understand what `extract(Some(1))` or `extract(Ref(1))` or `extract(Val(1))` would be doing if they see its documentation is saying `extract a single canonical value from a wrapper`.

Sure, but that’s not my point. I’m saying that if you’re already expecting a `Some` there, why use the (generic) `extract`, when there’s the explicit `something` for unwrapping, which explicitly shouldn’t take anything other than `Some`? I can’t imagine a case where I want to be generic over the “wrapper type” and don’t already care about getting a `Some` and its specific semantic meaning. The same goes for `Ref` (assign to a location somewhere other than my scope) and `Val` (lift a value to the type domain) - the wrapper type has a semantic meaning in the context its used in, beyond being a wrapper for something else.

I should also note that the comonad page I linked above is in a haskell package, not the main distribution. So by default, `Some` doesn’t act like a comonad (though functionally it probably can be).

---

<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: [October 17, 2023, 10:59am UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/16 "2023-10-17T10:59:15Z")

</div>

While we’re talking about this – WeakRef doesn’t have a function to unwrap. The docs just use the internal property (`.val` if I remember correctly).

---

<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: [October 17, 2023, 11:21am UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/17 "2023-10-17T11:21:13Z")

</div>

I’m a little confused (and maybe that’s part of the points being raised here) about what the unwrapping is for. The title says singleton wrappers, but it lists `Ref` and `Some`, which do not have singleton concrete types. A singleton type either has no fields or only has singleton-typed fields (which take up no memory in the instance), so whatever is being unwrapped is in the type parameters e.g. `T` in `Val{T}`. It’s different from indexing a `Ref{T}` or accessing the `.val` field of `Some{T}` for an _instance_ of `T`.

Aside, what is `Some` for? I read the docs and still don’t know why you would need to distinguish a “presence of `nothing`” via `Some(nothing)` from an “absence of a value” via `nothing`, I’ve only ever needed the latter.

---

<div class="post-metadata">

### Author: ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)
#### Post date: [October 17, 2023, 11:41am UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/18 "2023-10-17T11:41:22Z")

</div>

Personally I just define `_unwrap` manually in every single package 🙃

@Benny that’s a good point. I’ve argued previously that `unwrap` on `Val` is not the same as `unwrap` on `Ref`.

What we have is two separate requirements, both that currently lack consistent syntax:

1. unwrapping instantiated objects with a single field (Ref case)
2. unwrapping types with a single parameter. (Val{T} case)

We shouldn’t mix them.

1. should return the value of `Ref` like `= ref[]`, and not have methods for `Val`
2. should return `T` in `Val{T}`, and could be argued to return the type of `Ref` like `T` in `Ref{T}`

`unwrap` and `unwraptype`, or `extract` and `extracttype` could work.

---

<div class="post-metadata">

### Author: ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)
#### Post date: [October 17, 2023, 11:42am UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/19 "2023-10-17T11:42:49Z")

</div>

> [@Benny](#):
>
> why you would need to distinguish a “presence of `nothing`” from an “absence of a value”

When you don’t distinguish these two cases, the result of some functions becomes ambiguous: see [`findfirst` on dictionaries returns ambiguous result · Issue #29565 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/29565) for an example where you cannot tell whether the element was or was not found in the dictionary.

---

<div class="post-metadata">

### Author: ![nalimilan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nalimilan/32/147_2.png) [@nalimilan](https://discourse.julialang.org/u/nalimilan)
#### Post date: [October 17, 2023, 11:56am UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/20 "2023-10-17T11:56:32Z")

</div>

FWIW we had a similar debate recently about `unwrap` in DataAPI: [Don't define unwrap(x::Any) · Issue #59 · JuliaData/DataAPI.jl · GitHub](https://github.com/JuliaData/DataAPI.jl/issues/59#issuecomment-1625017672). The complaint is that we define a fallback `unwrap(x::Any) = x`, so we don’t throw an error if you accidentally call `unwrap` on a value which isn’t supposed to work in that context.

Also, as a historical point, when `Nullable` was a thing in Base, one would extract it using `get(x::Nullable)` (which throwed if the object was null) or `get(x::Nullable, default)`. This made sense because of the presence of `default`. The current equivalent of this pattern is `something(x::Union{Some, Nothing})` or `something(x::Union{Some, Nothing}, default)`.

[Next page](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003.md?page=2)
