# 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:** 17\
**Page:** 3

<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 17, 2023, 4:29pm UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/41 "2023-10-17T16:29:08Z")

</div>

> [@schlichtanders](#):
>
> My rule of thumb is that fields are implementation details of individual Types and don’t belong to generic APIs… but this is just gut feeling

Exactly! That’s precisely what I’m getting at with unwrapping — it’s really an implementation detail of an individual type and doesn’t belong to a generic API.

---

<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, 4:32pm UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/42 "2023-10-17T16:32:26Z")

</div>

I don’t share this opinion. The generic API is defined by the common understanding, and this is “extracting the single value of a single-value wrapper”.

This is not an implementation detail (by definition for me - you can define the single-value wrapper in many different ways)

---

<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, 4:37pm UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/43 "2023-10-17T16:37:55Z")

</div>

There’s nothing about “single value wrapper” that is really very generic though, at least in the sense that I’d want to use `Ref`, `Val` and `Some` interchangeably. The semantics of those three types individually are much more important than the fact that they can all hold only a single value.

As asked above - do you have an example for something where you’d be happy to accept either of those three and only care about the value inside, but NOT the fact that you got any specific one of these?

---

<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 17, 2023, 4:39pm UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/44 "2023-10-17T16:39:15Z")

</div>

But what is a wrapper and why do I want to remove it? Is a `Diagonal` a wrapper? What about `Set`? Is a `Ptr{T}` a wrapper? And if so, does it wrap a `UInt` or a `T`? All those things “wrap” a single field/value, too.

---

<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, 4:40pm UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/45 "2023-10-17T16:40:42Z")

</div>

> [@mbauman](#):
>
> Is a `Ptr{T}` a wrapper?

`Ptr{T}` is actually even worse, because it doesn’t necessarily hold a value of type `T` - truthfully, loading from the pointer can go wrong.

In fact, `Ptr{T}` doesn’t hold (or more precisely, own) the object it may or may not point to at all.

---

<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 18, 2023, 8:53am UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/46 "2023-10-18T08:53:50Z")

</div>

Many more builtin single-value wrappers!! Awesome. Yes this makes for a more complete picture.

> [@mbauman](#):
>
> Is a `Ptr{T}` a wrapper? And if so, does it wrap a `UInt` or a `T`?

If `Ptr` does not have a canonical single value to be extracted, then it probably does not fit this general `extract` api.

> [@Sukera](#):
>
> As asked above - do you have an example for something where you’d be happy to accept either of those three and only care about the value inside, but NOT the fact that you got any specific one of these?

Here my motivating example (I probably should have minified this way earlier in the discussion 😉) :

```julia
lang_specific(::Val{:jl}) = "this is very specific code to support .jl files"

function my_generic_func(langwrapper)
    # we have some helper functions which depend on a wrapper type which is not interesting to this "generic" function
    lang_specific(langwrapper)
    # instead of print you can imagine anything else which may depend on the actual value
    lang = only(langwrapper)
    print("the current language used is: $lang")
end

```

EDIT: while this case may count as “generic” function or not, in general the goal is really rather mental simplicity, so that I don’t need to think or search every time for the specific unwrapper (if there is one at all).

---

<div class="post-metadata">

**Author:** ![sijo](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@sijo](https://discourse.julialang.org/u/sijo)\
**Post date:** [October 18, 2023, 11:54am UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/47 "2023-10-18T11:54:53Z")

</div>

That’s indeed a good example where your proposal would help. But it’s quite the edge case…

Here’s a parodical analogy to better explain why I dislike the proposal:

> I can never remember all the ways of using values in Julia, so I’ve defined the following:
> 
> ```julia
> # Using a function means calling it
> use(x::Function, y...) = x(y...)
> 
> # Using a command means running it
> use(x::Cmd) = run(x)
> 
> # Using a mutex means locking it (call `unuse` to unlock)
> use(x::ReentrantLock) = lock(x)
> 
> # Using a regex means matching text
> use(x::Regex, y) = match(x, y)
> 
> # Using a channel with a value means sending the value
> use(x::Channel, y) = put!(x, y)
> 
> # Using an array means accessing the values
> use(x::AbstractArray, y...) = x[y...]
> 
> ```

Of course it’s not a fair analogy (“use” is more ambiguous than unwrapping). But I think it shows in which wrong direction this proposal is going: all code is going to look like a bunch of `use`. It’s hiding the semantics behind the types of the values. These types are often not obvious so the code is less readable. You basically have to run type inference in your head to make sense of it.

---

<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 18, 2023, 2:27pm UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/48 "2023-10-18T14:27:25Z")

</div>

I really don’t know what to take from it 🙂  
It sounds like a song against using common APIs. A bit like “always use the implementation detail if possible”.

> [@sijo](#):
>
> But it’s quite the edge case…

I don’t think so. I am relatively often running into this - probably as often as I am using `Val`, which is actually quite often. And others also reported to define their own `unwrap` method every time.

> [@sijo](#):
>
> You basically have to run type inference in your head to make sense of it.

I don’t have to run type-inference in my head in order to fruitfully use a function like `only`.

---

<div class="post-metadata">

**Author:** ![sijo](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@sijo](https://discourse.julialang.org/u/sijo)\
**Post date:** [October 18, 2023, 2:42pm UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/49 "2023-10-18T14:42:25Z")

</div>

> [@schlichtanders](#):
>
> It sounds like a song against using common APIs.

But do you agree this is showing a downside of your proposal? I agree there’s an upside in common API, maybe we just disagree on the weights of the upside and downside.

> [@schlichtanders](#):
>
> I don’t think so. I am relatively often running into this - probably as often as I am using `Val`, which is actually quite often. And others also reported to define their own `unwrap` method every time.

I’m saying the example is an edge case where the proposal makes things significantly easier. I think what you often run into is a wish for `extract` so you don’t have to remember which function to use? That’s quite different… And I suspect the `unwrap` defined by others fall in the same category.

> [@schlichtanders](#):
>
> I don’t have to run type-inference in my head in order to fruitfully use a function like `only`.

The problem is more when you read code written by others (or a younger self), to understand what the `only` call (and the code around it) is really doing.

---

<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 18, 2023, 2:51pm UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/50 "2023-10-18T14:51:57Z")

</div>

> [@sijo](#):
>
> I think what you often run into is a wish for `extract` so you don’t have to remember which function to use? That’s quite different… And I suspect the `unwrap` defined by others fall in the same category.

yes, exactly (and sometimes there even is no function, and in case of Val there even is no field)

> [@sijo](#):
>
> The problem is more when you read code written by others (or a younger self), to understand what the `only` call (and the code around it) is really doing.

This is great test to check whether something is really more useful than harmful. I like it a lot. Cannot say whether my later I would be confused by `only`.  
I guess a bit, but only so far as I am not yet used to its already established meaning. Hence, only so far as people already get confused by `only` when they seeing it the first time being applied to a Vector.

---

<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 18, 2023, 2:56pm UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/51 "2023-10-18T14:56:16Z")

</div>

That `my_generic_func ` example is actually perfect for expressing the troubles with this. It _looks_ like it could support any language implementation. I could decide it’s worth adding support for Javascript with a struct that needs a parsing state machine:

```julia
struct JS
    parser_state::StateMachine
    JS() = new(StateMachine())
end

```

Now what happens when I try running `my_generic_func(JS())` — and importantly, does `JS` implement an unwrap/only method to access its state machine? If so, suddenly you’re telling folks about the internals of its state machine instead of the language you meant. Now you may say: OK Matt, that’s pretty contrived — just don’t implement unwrap/only for it! But let’s take it one step farther. Let’s implement a specific parser for JSON that wraps a JS parser and just limits the language in a few specific ways:

```julia
struct JSON
     language::JS
end

```

Now here it seems useful to access the underlying language in some contexts, no? Let’s implement unwrap for it! Oh, wait, now your `my_generic_func` is even more subtly wrong: it’s reporting `JSON` inputs as `JS`.

The answer is that your `my_generic_func` isn’t generic. It’s implicitly dependent upon `my_generic_func(langwrapper::Val)` and will break in unexpected ways if you pass anything else.

To put a slightly finer point on it, the problem isn’t so much that “unwrapping” isn’t well-defined, it’s that _wrappers themselves_ aren’t well defined. You might wrap a meaningful name, but you also might wrap an internal piece of machinery, or maybe you wrap an externally-visible thing to slightly change its behavior, or maybe you wrap something entirely different.

---

<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 18, 2023, 3:27pm UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/52 "2023-10-18T15:27:31Z")

</div>

while I don’t understand your example on the first read through, I guess you are telling, that I should rather define a `getlangsymbol` unwrapper, which specifically targets my usage of the unwrapping I need. I need more time to think about it.

(Of course in my example I was rather looking for something builtin, so that I don’t need to define an extra ~~type~~ function - you seem to be telling, that there couldn’t be any helpful builtin… because of the concept of “wrapping” being ill-defined… need to think a bit more about it. )

---

<div class="post-metadata">

**Author:** ![jlapeyre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlapeyre/32/4514_2.png) [@jlapeyre](https://discourse.julialang.org/u/jlapeyre)\
**Post date:** [October 18, 2023, 3:36pm UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/53 "2023-10-18T15:36:54Z")

</div>

> It does not mean that we’re free to invent new semantics for what a function means.

Actually we _are_ free to invent new semantics for functions. People do it frequently. I certainly believe that we _ought_ not do it. An example is SymbolicUtils which uses `==` not to compare values (returning `Bool`), but rather to construct an equation. And then extends `Base.isequal` to compare two values of types in the package, when the docstring says `isequal` is concerned with “treatment of floating point numbers and of missing values.”

I always trot out this example. I could find another example to avoid always pointing my finger in the same place. I would not be surprised to find a similar abuse of multiple dispatch in a package I wrote, especially an older one.

---

<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 18, 2023, 3:57pm UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/54 "2023-10-18T15:57:53Z")

</div>

The discussion here is about adding/changing Julia’s builtin definitions, which requires clearing a much higher bar.

---

<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 19, 2023, 7:55am UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/55 "2023-10-19T07:55:12Z")

</div>

I have read up some comonad literature and realized that there is paradigm example called the Store Comonad ([reference](https://bartoszmilewski.com/2017/01/02/comonads/)).  
At the end it says, it is the base for the concept of a _Lens_, i.e. of getters and setters, just without having the fieldname which you want to set/get.

This intuition reminds me a lot of the two Julia apis

```julia
getindex(a) # a[]
setindex(a, s) # a[] = s

```

which are exactly supported by `Ref`.

* * *

I guess **indexing** captures very well where my goal lies between implementation detail and having a semantically fully specified api (like in the example `getlangsymbol`): **It is more a generic helper to work with structure.**

A wrapper of a wrapper of a wrapper of course would need nested indexing, but nevertheless people somehow agreed that indexing is a valuable concept. You can build another helper-wrapper which somehow simplifies indexing into a complex nesting of wrappers. That all fits the general idea of indexing (a kind of unstructuring if you will).

Given this thought, I am surprisingly coming to the intermediate conclusion that `getindex` might be the most fitting general api for “unwrapping a single-value wrapper”. (of course `get` and `only` also have a relation to the concept of unstructuring, but for me it feels slightly less so)

---

<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 19, 2023, 3:59pm UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/56 "2023-10-19T15:59:25Z")

</div>

Sure! Then the key question is if the type wants to fully behave like an indexable (and likely iterable) container of one element. And then there’s a whole host of well-documented and defined expectations and behaviors that come with that decision.

It’s not always obvious if all those semantics are what you want, though, and there are big ramifications about how the thing behaves in other parts of Julia — like broadcasting, for example.

---

<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 21, 2023, 8:20am UTC](https://discourse.julialang.org/t/unifying-unwrapping-single-value-wrappers/105003/57 "2023-10-21T08:20:43Z")

</div>

> [@mbauman](#):
>
> IMV the place to standardize the `parent` language is in the field name. Then you know you’re doing something very particular to the type through field access, but still have a common vocabulary. Perhaps the same is true here, but with `.value`?

Now I also better understand this comment of yours.  
A field access is also some kind of destructuring, similar to indexing

### Downsides of field access

existing single-value wrappers have different fields already … this is probably hard to unify

### Downsides of `getindex`

indexing often comes with supporting iterable (e.g. Ref does so), but this might unwanted by certain wrappers.

I think indexing would be great, but only if it is allowed to come without supporting iterator.

> [@mbauman](#):
>
> whole host of well-documented and defined expectations and behaviors

@mbauman which documentation are you referring to?

### Downside of a new function

With the new understanding, that this needs to make sure that people understand it as a kind of unstructuring like field access or indexing, I think get and only are suboptimal.  
While `unwrap` seems to go into the right direction, it can understand that might be probably confusing as a general api.  
It is hard to think of another name which makes clear that this is an unstructuring process similar to getindex or field access…

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