Struct fields as arguments

Thanks, I guess I get it: INVERTING DATA ACCESS. :slight_smile: might be what I need. Unfortunately, I am not a pro in either of the Langs you mentioned.

I will try inverting data access (possibly with the |> operator) and see where I can get.

Best,

Then try with any other language you are proficient with. We have quite some polyglots here in the forum.

From the questions you ask, it seems as if you have used at least one OOP language so far.

1 Like

Yep this! I excessively know a lot of languages from C/C++ to Java to OCaml to Python to Perl to I’m learning Rust right now to so so so many more of various levels. A lot of people are like that here. :slight_smile:

The BEAM is a great glue language to other languages too, I’ve known erlang since 2001 or so (maybe earlier, I remember when HiPE was added…). ^.^

1 Like

Thanks Gentlemen,

I will provide all the modules that I have built. I have stripped many of them so that the code is not too bulky. Probably, by doing this (as a newbie) I may help others who may run into similar difficulties.

So far, I have 4 module: LangEngine.Type, LangEngine.Subtype, LangEngine.ContentObject, and LangEngine.Component.

defmodule LangEngine.Type do
  @type_list [:text, :media, :widget]
  def new(input) do
    msg = "Your input is not a valid type"
    case Enum.member?(@type_list, input) do
      true  -> input
      false -> %{error: msg}
    end
  end

  def new() do
    msg = "You have not provided a type"
    %{error: msg}
  end

  def valid_type?(type) do
    case Enum.member?(@type_list, type) do
      true  -> true
      false -> false
    end
  end
end
defmodule LangEngine.Subtype do
  alias LangEngine.{Type}
  @text_list [:h1, :h2, :h3, :h4, :h5, :h6, :p]
  @media_list [:image, :audio, :video]
  @widget_list [:button, :submit, :input, :password, :link, :textarea]

  defstruct name: nil

  def new(type, input) do
    case Type.new(type) do
      %{error: msg} -> %{error: msg}
      :text -> validate_subtype(@text_list, :text, input)
      :media -> validate_subtype(@media_list, :media, input)
      :widget -> validate_subtype(@widget_list, :widget, input)
    end
  end

  def new(_input) do
    Type.new()
  end
  def validate_subtype(list, type, input) do
    msg = "Your input (#{input}) is not a valid subtype of the provided type (#{type})"
    case Enum.member?(list, input) do
       true -> input
       false -> %{error: msg}
    end
  end

  def valid_subtype?(type, input) do
    case new(type, input) do
      %{error: _msg} -> false
      _input -> true
    end
  end
end
defmodule LangEngine.ContentObject do
  alias LangEngine.{ContentObject, Type, Subtype}
  @enforce_keys [:id, :type, :subtype]
  defstruct id: nil, type: nil, subtype: nil, content: nil

  def new(id, type, subtype, content) do
    if Type.valid_type?(type) == true do
      if Subtype.valid_subtype?(type, subtype) == true do
        %ContentObject{id: id,
              type: type,
              subtype: subtype,
              content: content}
      else
        Subtype.new(type, subtype)
      end
    else
      Type.new(type)
    end
  end
end
defmodule LangEngine.Component do
  alias LangEngine.{Component}

  @enforce_keys [:id, :content_objs]
  defstruct [id: nil, content_objs: []]

  def new(id, content) do
    %Component{id: id, content_objs: [content]}
  end

  def simple_component_view(component) do
    for obj <- component.content_objs do
      %{:name => obj.id, :subtype => obj.subtype}
    end
  end

  def update_component_content(component, new_content) do
    %Component{id: component.id, content_objs: [new_content]}
  end
end

These modules compile with no errors or complaints.

Now, back to my original question: It seems that I was thinking of a data of type “Component” as a container of ContentObject, and ContentObject as a container of Type and Subtype. I NOW think this is true, but not in the OOP way. The contained data in either ContentObject and Component are not objects with references. Once created, they are set. If I create a component with Component.new, what I will get is a piece of data, and not an object. What this means is if I now go and change one of the contained data pieces (say, the type or subtype) I will not get a new component immediately. I will need a function to do that. This is why I created a function in the Component Module with the name “update_component_content”.

The amazing thing is in iex I can have a variable and bind it to a new “component” with a certain “content object”, then go change that content object, then rebind my variable using “update_component_content” function, and when I ask iex for what value my variable is it will respond with the updated component, so to speak.

However trying to do this in a function in the Component module, and trying to pass a component as an argument gave me that warning of “… is not being used”.

I am sorry if I am taking too much space, or providing irrelevant details, but I think that providing some real code written by a newbie might shed a light on:

  • non idiomatic ways that may be in my code
  • some mental barriers the code reveals.

Many thanks again for all who have replied to me.

N.B: I tried my best not to use the term object so that NoobZ doesn’t flame me :slight_smile:. Instead I used the word “data”.

Hassan

You can just not use data = … And just return your modified struct. No need to rebind it. That should get rid if the original error.