# Empty vs. value types, and vectorisation

**URL:** https://discourse.julialang.org/t/empty-vs-value-types-and-vectorisation/20433
**Category:** New to Julia
**Created:** [February 4, 2019, 4:21pm UTC](https://discourse.julialang.org/t/empty-vs-value-types-and-vectorisation/20433 "2019-02-04T16:21:41Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![asprionj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/asprionj/32/6856_2.png) [@asprionj](https://discourse.julialang.org/u/asprionj)
#### Post date: [February 4, 2019, 4:21pm UTC](https://discourse.julialang.org/t/empty-vs-value-types-and-vectorisation/20433/1 "2019-02-04T16:21:41Z")

</div>

I’m quite new to Julia and am currently starting my first “real” project. One of the “innermost” things I have to implement are properties of various liquids, for example the density, as a function of temperature. I’m not sure which is the correct way to implement this in Julia, so thanks for your advice.

The liquids share no common data, so I went with “empty” types:

```julia
abstract type Fluid end
struct Water <: Fluid end

```

Then, define the property functions, e.g.:

```julia
density(::Water, th) = 1000.0 - th/100.0 # not physically correct ;-)

```

Evaluating the properties then is like:

```julia
myfluid = Water()
density(myfluid, 273.0)
density.(myfluid, [273.0, 300.0])

```

But the second call (`density.`) throws the MethodError that there’s no method for `length(::Water)`.

**My questions:**

1. Would using a value type be more appropriate here? E.g.:

```julia
struct Fluid{name} end
Fluid(name) = Fluid{name}()

density(::Fluid{:Water}, th) = ...

myfluid = Fluid(:Water)
...

```

1. What’s the preferred way of enabling “vectorisation” / broadcasting in such a case? I could define the property functions in a vectorised form, e.g.  
`density(::Water, th) = 1000.0 .- th./100.0`. This would allow to use them with arrays for `th` as well, but with the same “not-obviously-broadcasted” function name without trailing dot. Can I somehow tell Julia that `::Water` is always scalar? I don’t want to implement all required `AbstractArray` methods accordingly.

2. Is there a better way in general to implement this all in Julia?

---

<div class="post-metadata">

### Author: ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)
#### Post date: [February 4, 2019, 4:33pm UTC](https://discourse.julialang.org/t/empty-vs-value-types-and-vectorisation/20433/2 "2019-02-04T16:33:00Z")

</div>

Your first question should be: Do specific fluids really want to be a type? That is, do you know what fluid you are dealing with at compile time? If you have heterogenous datastructures (mixing e.g. `Fluid{:Water}` and `Fluid{:Oil}`), then this won’t perform well.

Regarding the broadcasting, this is a case where closures/anonymous functions could be appropriate:

```julia
function foo!(densities, temperatures, fluid)
densities .= (th-> density(fluid, th)).(temperatures)
nothing
end

```

This snipped is agnostic about whether kinds of fluids are a type or an integer / UInt8 / enum used for lookups in global tables (and I’d guess you can expect to do some refactoring along these lines in the future).

---

<div class="post-metadata">

### Author: ![asprionj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/asprionj/32/6856_2.png) [@asprionj](https://discourse.julialang.org/u/asprionj)
#### Post date: [February 4, 2019, 4:51pm UTC](https://discourse.julialang.org/t/empty-vs-value-types-and-vectorisation/20433/3 "2019-02-04T16:51:46Z")

</div>

> [@foobar\_lv2](#):
>
> Do specific fluids really want to be a type? That is, do you know what fluid you are dealing with at compile time?

Yes, I do know at compile time what the fluid is. That’s why I wanted to avoid an enum and case-switching at runtime. One detail: the methods for the properties of different fluids are not the same, so I cannot just lookup coefficients.

Thanks for your proposed solution for broadcasting (and doing in-place evaluation at the same time). One can surely do it this way, but overloading the out-of-place but broadcasted `density.` using this approach is not possible.

---

<div class="post-metadata">

### Author: ![chakravala](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chakravala/32/6832_2.png) [@chakravala](https://discourse.julialang.org/u/chakravala)
#### Post date: [February 4, 2019, 10:15pm UTC](https://discourse.julialang.org/t/empty-vs-value-types-and-vectorisation/20433/4 "2019-02-04T22:15:00Z")

</div>

The parametric type would be preferable, in my opinion. The reason is, you probably are only dealing with a small number of fluids, so you want this information to be included at compile time.

---

<div class="post-metadata">

### Author: ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)
#### Post date: [February 4, 2019, 10:37pm UTC](https://discourse.julialang.org/t/empty-vs-value-types-and-vectorisation/20433/5 "2019-02-04T22:37:26Z")

</div>

> [@asprionj](#):
>
> Can I somehow tell Julia that `::Water` is always scalar?

Yes, definitely! The full interface is documented here: [Interfaces · The Julia Language](https://docs.julialang.org/en/v1/manual/interfaces/index.html#man-interfaces-broadcasting-1) but I believe all you actually need to do is define: `Base.broadcastable(f::Fluid) = Ref(f)`

Using a Ref is also the recommended way to force a particular argument (regardless of its type) to behave as a scalar in a broadcasting expression. For example, `foo(bar, Ref(baz))` will broadcast over the elements of `bar` but treat `baz` as a scalar (even if `baz` happens to be, for example, an array)

---

<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: [February 4, 2019, 10:38pm UTC](https://discourse.julialang.org/t/empty-vs-value-types-and-vectorisation/20433/6 "2019-02-04T22:38:39Z")

</div>

Check out a previous answer of mine on this topic:

> [@Overhead of dynamic dispatch?](https://discourse.julialang.org/t/overhead-of-dynamic-dispatch/7089/5):
>
> There are a number of downsides to encoding a property of your thing in the type system: There will be more time spent in compilation — every time a different type hits a different function, Julia will compile a new specialized version just for that type. If this property is typically determined by a run-time value, then many functions working with your things will be type-unstable. Type-unstable variables can stymie optimizations, cause allocations and hit dynamic dispatch. Collections of ma…

Both your approaches (`Fluid{:Water}` and `Water <: Fluid`) encode `Water` into the type-system — and I’m not sure there’s a big semantic difference between the two. I think I’d prefer the abstract/struct one if that’s going to be the way you go… but you may want to consider if you actually need this encoded in the type system in the first place.

---

<div class="post-metadata">

### Author: ![asprionj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/asprionj/32/6856_2.png) [@asprionj](https://discourse.julialang.org/u/asprionj)
#### Post date: [February 5, 2019, 7:27am UTC](https://discourse.julialang.org/t/empty-vs-value-types-and-vectorisation/20433/7 "2019-02-05T07:27:52Z")

</div>

> [@rdeits](#):
>
> I believe all you actually need to do is define: `Base.broadcastable(f::Fluid) = Ref(f)`

Thanks, this actually seems to be the right way to enable broadcasting in this case (since I know that the fluid type is not used in any calculation but solely for dispatching the correct method).

> [@mbauman](#):
>
> If this property is typically determined by a run-time value, then many functions working with your things will be type-unstable.

As I mentioned above, in this case, the fluid is known at compile time (it is set as a “global property” of an overall model). I see your point for run-time determined properties; I wouldn’t encode this into types neither.

> [@mbauman](#):
>
> but you may want to consider if you actually need this encoded in the type system in the first place.

How would you suggest to do it? Using an enum and case switching in each function? That makes the code a bit less modular: for adding new fluids, one has to add another case in each function, and also to some docstring or some tuple that ca show the user all available fluids. Also, wouldn’t Julia then compile all possible branches at once, whereas with type-specific methods, only the relevant one gets compiled?
