Fl4m3Ph03n1x

Fl4m3Ph03n1x

I have the following code where I test for the existence of an ETS table:

case :ets.whereis(:metrics) do
      :undefined                  -> {:error, :table_not_created}
      tab when is_reference(tab)  -> {:ok, :ready}
      _                           -> {:error, :unable_to_veify_table}
end

However, the clause is giving a weird error:

Guard test is_reference(_tab@1::ets:tid()) breaks the opacity of its argument

What does this mean and how can I fix it?

Showing Posts 1 to 10

LostKobrakai

LostKobrakai

You can’t really fix it. :ets.whereis returns the opaque type tid() but your guard clause does typecheck on it. This means you’re dealing with internals you’re not supposed to deal with.

Ted

Ted

I just read about opaque types yesterday in Programming Erlang and my understanding is a little hazy.

In this case, :ets.whereis returns an opaque value, and my assumption is that this value can only be poked and prodded by other functions in the :ets module.

My nascent mental model is akin to handling radioactive materials: the material is locked away in a safe box and we can only handle it by sticking our hands into the gloves attached to the box.

Am I off base with my thinking?

peerreynders

peerreynders

In my mind an opaque type is the equivalent to the OO design guideline that all instance data should have non-public access.

In OO one motivating factor is that you don’t want anything but the instance methods mutating the instance data. In a world where everything is immutable by default that really isn’t an issue which explains to some degree why functional languages can rely on plain data structures so much.

However direct access of the client to the data to the internal organization of the data structure still couples the client to that specific organization.

An opaque type breaks that type of coupling as the client is now forced to use the functions that are supplied with the data structure to extract any information.

When done right an opaque type can give the freedom to radically change the implementation while keeping the API of client facing functions stable (example - here names could be typed as @opaque).

Fl4m3Ph03n1x

Fl4m3Ph03n1x OP

I understand that argument, but since :ets.whereis is part of the public API, shouldn’t the result not be opaque? My understanding is that it’s fine if I depend on the result a given public function returns me, because that’s part of the public API and not an implementation detail.

Am I missing something?

peerreynders

peerreynders

It’s complaining about is_reference - right now tab is a reference but in the future that reference may be buried deeper inside another data structure (now representing an ets table) altogether.

garazdawi

garazdawi

Erlang Core Team

It actually used to be an integer not very long ago, so :ets is a very good example of this.

Fl4m3Ph03n1x

Fl4m3Ph03n1x OP

@peerreynders
If you change the return value of a public function, you change the public API of the module.

Yes, I defend my code should not depend on internal data structures. That’s why modules usually don’t expose their internals to the world and that’s also the why of getters and setters. But if I can’t even rely on the results of your public API, what can I rely on ?

Values returned from a public API are part of the API. Just like if someone changes :ets.whereis to receive 10 parameters instead of 1, that is a change to the public API.

Do we agree on this? I feel I need to establish some common ground before moving on.


@garazdawi

Interesting feedback, thanks for the info !

sasajuric

sasajuric

Author of Elixir In Action

You can rely on the fact that all the :ets functions work correctly if you pass them the result of :ets.new, regardless of what the actual return value is. As long as you do that, and don’t assume anything about the actual data in the tid type, you shouldn’t experience any breaking changes if the tid type is changed.

Fl4m3Ph03n1x

Fl4m3Ph03n1x OP

I am sorry but I seem to be understanding something among the lines of “don’t bother with the return values of the public API and you will be fine”.

Which sounds completely … well… let’s say unreasonable. Am I the only one that sees it this way?

garazdawi

garazdawi

Erlang Core Team

You can rely on the documentation. For ets, the documentation says that you will get a tid() or undefined back. The documentation never states what tid() is, so you cannot assume in your code what it is.

The same is true for any opaque datatypes, i.e. dict(), array() etc etc.

Where Next? Top

Trending in Questions Top

stjefim
Hello! Suppose you are building workflow (order / task / payment) processing system with the following requirements: Each workflow con...
New
jonnycharles
I’m in search of an Elixir library that offers PDF generation capabilities similar to Ruby’s Prawn. While there have been discussions abo...
New
spammy
I’m looking to build a personal workflow to quickly deploy web applications written in elixir/phoenix, for local consumption (ie not on t...
New
dli
Before I dive in myself, did anyone successfully sprinkle Hologram into their existing LiveView app? Looking for hints regarding: Addi...
New
roeland
Kia ora, We have been using elixir-google-api to connect to Google Drive. However, with the updates to Tesla due to CVEs this is now bro...
New
bottlenecked
Hi all, I wanted to ask how the community is dealing with post-release steps. Today we have Ecto migrations, which make sure that the db...
New
rahultumpala
Hello, I have an Elixir backend that implements a custom protocol over TCP. I want to load test the backend and assess the performance o...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews