Crowdhailer

Crowdhailer

Creator of Raxx

Should libraries implement default callbacks that are intended to always be overwritten?

My opinion very much undecided on this Question so all comments welcome.

This is probably best discussed using the concrete example I am considering at the moment in Raxx.
(Raxx has the goal of being a capable toolkit for developing lean web applications in Elixir.)

For simple endpoints applications implement the Raxx.SimpleServer behaviour.
Simple endpoints are when streaming is not required for either request or response, if streaming is required then the Raxx.Server behaviour is implemented

A simple example would look like the following.

defmodule MyServer do
  use Raxx.SimpleServer

  @impl Raxx.SimpleServer
  def handle_request(%{method: :GET, path: []}, _state) do
    response(:ok)
    |> set_header("content-type", "text/plain")
    |> set_body("Hello, World!")
  end
end

The line use Raxx.SimpleServer defined a default implementation of handle_request/2 which any application is always expected to overwrite.
The default implementation shows a page that explains what a user should be implementing, and this is done to help users.

https://github.com/CrowdHailer/raxx/blob/master/lib/raxx/simple_server.ex#L105-L111

I am no revisiting this choice for the following reasons.

  • behaviours create a compile time warning when one of their callbacks is not implemented,
    this is lost by implementing a default. Any mistakes are found only at runtime, hopefully by tests.
  • Safely generating this page required adding a dependency on eex_html, this dependency is included only to render pages that should never be rendered in a correctly set up application
  • These helper pages are useless if the client is not a human. i.e. when making api services.

In summary I am thinking of removing this default because a compile time warning is more useful than any information that might be show at runtime in the page, and in any case is just a copy of the information available in the documentation

Most Liked

josevalim

josevalim

Creator of Elixir

FWIW, we have been slowly migrating away from default implementations and using optional callbacks instead. If the user wants warnings, then @impl is the way to go. There is an old discussion about it here: Behaviours, defoverridable and implementations

OvermindDL1

OvermindDL1

What phoenix does in such cases (like router callbacks into controllers and so forth) is it has a ‘jump’ function (action I think?) that is what actually calls the appropriate method, and if it throws, like it doesn’t exist, then it reports it as such. This means you don’t get compile warnings though as it’s an apply, however with macro work to ‘bake in’ the calls without using apply you could get the best of both worlds? It would require making a pre-call function in that same module and calling that instead, and having it call the real function that needs to be overridden. That would give both a warning, maybe even an error at compile-time, but if such a thing does somehow make it through then it would give a good message.

On the other hand, making a public function with a (mostly) uncallable name that just calls the functions that needs to be implemented locally then it wouldn’t compile if they didn’t exist, but you’d need to craft good default data to let dialyzer handle it properly and that can be pretty hard to do without taking ‘opaque’ arguments in (this function would never actually be called, it’s sole purpose is just to require those functions).

Although at that point you could just analyze the module info(:functions) at compile time from the thing that calls those implementations and verify they exist first, but that would involve requiring those files to be compiled first and the beam files to be scanned.

Honestly, I’d say just implement a behaviour, no default implementations, and let the compiler handle it as normal. :slight_smile:

LostKobrakai

LostKobrakai

If you want to have a descriptive error page I feel it’s in the same realm as the phoenix error page with the debugging information: Enable it in :dev, but fail for other environments.

Where Next?

Popular in Discussions Top

Donovan
Hello everyone, I’m so glad to have discovered this awesome community. Thanks for creating it! This is my second post, and apologies for...
New
Fl4m3Ph03n1x
Background This question comes mainly from my ignorance. Today is Black Friday, one of my favorite days of the year to buy books. One boo...
New
lorenzo
Hey everone! I created a prototype for my app using Nodejs for the api. But the framework I chose wasnt great (in general theresnt any g...
New
boundedvariable
I am going through the kafka architecture. All the features what the kafka is providing are already in Erlang. I would like hear your opi...
New
und0ck3d
Hello everyone! A few days ago I’ve created a topic here about how people were creating CMSs with Elixir and Phoenix. I’ve been studying...
New
chulkilee
Here are the list of HTTP client libraries/wrappers, and some thoughts on HTTP client in general. I’d like to hear from others how they w...
New
AstonJ
Can you believe the first professionally published Elixir book was published just 8 years ago? Since then I think we’ve seen more books f...
New
JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1144 54250 245
New
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New
Markusxmr
Since Drab has been developed for a while in the open, introducing the Liveview functionality in a way it happend appears to undermine th...
New

Other popular topics Top

hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a > b) do {:ok, "a"} end if (a < b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

We're in Beta

About us Mission Statement