Binding vars inside `cond`?

the problem with Process dictionary is that there’s no fetch function, so if your function returns nil or :undefined, it’s not going to be cached, since there’s no way to determine whether the value is cached or has not been cached yet. Please someone correct me if I’m wrong.

2 Likes

You’re not wrong in general; the specific code in the question was comparing the result of an_expensive_function_returning_b to c with <, so I assumed it couldn’t be nil since such a comparison will work but is almost certainly not useful.

In a general situation where the expensive function could return nil, you’d need to wrap the value in something to distinguish “not in the dictionary” from "present but nil", for instance an :ok tuple:

defp b_cache_wrapper do
  case Process.get(:an_expensive_function_returning_b_cache) do
    nil ->
      result = an_expensive_function_returning_b()
      Process.put(:an_expensive_function_returning_b_cache, {:ok, result})
      result

    {:ok, cached_value} ->
      cached_value
  end
end
3 Likes

I am not sure I understand. Unless I am missing something I either would need to write the ETS handling wrapper myself or pull-in another dependency like for example this one. Now both are surely possible if justified. But…

… precisely :slight_smile: That’s why I liked @al2o3cr’s suggestion, which does exactly that, and (as long as no IPC is involved) requires neither additional deps nor additional ETS handling

It was dummy code. In reality one of the expensive calls can return nil, but…

… in this particular case even if it does return nil, this is already triggering error so it wouldn’t be called again ergo no problem. Still it would be much better to handle also the “valid” nil, and…

… this looks to me like a nice, Elixirish way to do it :slight_smile:

Ah, i presume too much, i was presuming you are dealing with similar problem i frequently deal at work:

  1. Calling expensive function is not a single isolated incident, you have relatively big codebase which have frequent problem of calling expensive function multiple time.
  2. your codebase heavily rely on async / Task function.

In which case, it would be nice to have a generic cache wrapper module/function, which you could plug in wherever you need at problematic hotspot. I was creating custom module based on Cachex, but it’s spirit is similar to GitHub - cabol/nebulex: In-memory and distributed caching toolkit for Elixir. or GitHub - melpon/memoize: A method caching macro for elixir using CAS on ETS.

1 Like