What represents the syntax: #Module.Name<fields>

Hello everybody,

I understand so far that there is no Objects in Functional Programming. So everything is about Data and their transformation using Functions.

So using structs to represents data makes a lot of sense in Elixir. And instead of a function returning an Object we can have a function that returns a struct.

And I know that a the syntax for a struct uses % and {} eg. like %User{}

Now, I’m playing in iex with Phoenix and Ecto and I noticed the following syntax:
data: #MyApp.User<>

In this example I simply logged an Ecto changeset using MyApp.User.changeset(user, attrs) where I have a User schema that I know automatically defined the following struct: %MyApp.User{}

But what is this syntax with # and <>?

I looked in the Ecto source code (regarding this example of logging of a changeset) and the best I can found is that it’s a plain hash that is being returned…

Is it just a particular display formatting of a struct, or is it a kind of a data structure (not to say an object…) different from a plain struct?

This is the format returned for the Inspect protocol for a struct. So its not syntax per se, just a representation to aid in debugging (which is what Inspect protocol is primarily intended to serve).

Is starts with a # in part because if you cut and paste it will be a comment.

3 Likes

When implementing inspect one usually inspects into valid syntax for recreating data, though sometimes this isn’t wanted due to opaqueness of types or other abstractions made. So it’s convention to use # then to denote “this is a read only representation of the data, you can’t use this in code directly”.

4 Likes

I didn’t yet learn about protocols… But if I do IO.inspect on a regular struct I got the following output:

iex> IO.inpect %MyStruct{}
%MyStruct{data: nil}

So is it something that we can apply or not on a per basis situation?

That’s the default implementation for Any as a fallback. It will leak all potential internals of your struct.

For a MapSet the default would look roughly like this:

%MapSet{s: %{foo: true, bar: true}}

The overriden implementation makes it much more readable and doesn’t leak internal representation of the set:

#MapSet<[:bar, :foo]>
1 Like

Thanks for all the details…

Just a quick question before I leave… How I can override the default implementation?
Just some directions might be sufficient meanwhile I reach protocols in Elixir (if protocols are involved btw)

Just defimpl Inspect, for: ... and yes, that’s protocols.

1 Like