New to Elixir and a little confused by this snippet

def call(%Plug.Conn{request_path: "/" <> name} = conn, opts) do
  send_resp(conn, 200, "Hello, #{name}")
end

Am I correct in understanding that the struct on the left is updated with the values on the right and the “name” variable was declared & initialized at the same time?

Nope. ^.^

%Plug.Conn{request_path: "/" <> name} = conn is a ‘match’, not an assign or mutation (there is no mutation in this language). It is basically saying that whatever is passed in at this position will be bound to the name of conn, and that this conn must be a struct of %Plug.Conn{}, in addition take the field of request_path inside that struct and make sure it is a binary that starts with "/" and take whatever is after the "/" and bind it with the name as name so I can use it later. :slight_smile:

Also, there are no variables, so saying "name" variable was declared and initialized is entirely wrong, there are no variables, just categorically none, at all. :slight_smile:

3 Likes

This is very helpful. Thank you for taking the time straighten me out.

No problem, it is fun! Functional languages are definitely a different way of thinking, but well well worth it. :slight_smile:

1 Like

As someone new to functional programming I was going to hazard an answer. Good thing @OvermindDL1 responded before I did.

As I understand it, the parameter passed to the call , ie a %Plug.Conn must be a pair consisting of a conn object and some opts, and the request_path of that object must be a / followed by a string.

It doesn’t really say whether name may be the empty string, but another variant of call may match a request_path starts with a ‘/’ and has nothing after it, ie name = ''.

At this state I am not sure whether the call is part of the Plug DSL or is pure Elixir. I am still learning myself and await @OvermindDL1’s corrections

1 Like

Heh, nope. ^.^

Rather the call/2 is just a normal function, nothing special about it, it takes two parameters, the first must be that connection struct, the second is whatever options you pass in. The request path in the conn object must start with a /, but it can indeed be empty after that, or contain anything at all.

It can be empty, it can be full, but regardless it will be a binary. You can test to ensure a length of whatever else you want in a when conditional too, but that was not done here, so it can indeed be empty. :slight_smile:

call/2 is just a normal function, nothing special about it at all.

It is ‘used’ by the Plug DSL though, the only thing that DSL does is call init/1 at compile-time, takes the return value of that, and bakes that in as the second parameter to call/2, thus when call/2 is called it gets the conn right now and the second parameter is whatever the return value of init was. :slight_smile:

It is all just normal functions though, nothing special about that.

2 Likes

Does that mean that there could be a number of call/2 function definitions in the module, and that this function in particular would be the one called if the request_path of the conn struct matched / <> name?

I take it opts could be of any type so long as it was of the type expected by the code which was applied to it.

1 Like

Precisely! They are checked in order of definition, so you could put a fallback in after it for example, and it would be called only if the request path did not start with a /. :slight_smile:

(EDIT: Do note they must all be adjacent, so you cannot define a blah/0 function between two call2 functions, all definitions must be adjacent to each other.)

Also precisely! :smiley:

2 Likes