[erlang-questions] Update with complicated data structure
YuanZhiqian
on-your-mark@REDACTED
Tue Nov 24 08:53:27 CET 2015
Hi Brujo,
Thanks a lot. I think your approach is a best practice for these common data access in erlang. I am reading your codes to digest more details :)
Best regardsZhiqian
From: fernando.benavides@REDACTED
Subject: Re: [erlang-questions] Update with complicated data structure
Date: Mon, 23 Nov 2015 10:12:43 -0300
To: on-your-mark@REDACTED
Hi Yuan,
First of all, I usually use maps these days, not records. But, in any case, my usual approach is to hide data structures in their own modules, like the ones in this lsl folder (I’m talking about lsl_matches, lsl_players and lsl_sessions). Each one of them provides an opaque type to represent the entities they manage, along with functions to create/update/etc… the entities. If multiple simultaneous modifications are required by the system, I usually add an update function like:
-spec update(entity(), updates()) -> entity(). update(Entity, Updates) -> Entity1 = maps:merge(Setting, Updates), Entity1#{updated_at := calendar:universal_time()}.
That one works just because both entity() and updates() are maps. Sometimes (most of the times) update functions are more complex than that. In any case, business logic related to the entities is usually placed on the entity_repo modules (you can also find examples of them on the aforementioned folder).
Hope this helps :)
PS: You should use reply-all, so that your emails reach the erlang-questions mailing list as well :)
On Nov 23, 2015, at 10:01, YuanZhiqian <on-your-mark@REDACTED> wrote:Hi Brujo,
Thank you very much, that's a much better solution :) But still, I wonder how you and other guys normally deal with heavy works of states maintaining, since every time I want to update the system state, I would have to assign a new variable and pass it everywhere with function calls to maintain the records.
I have checked out ETS (erlang term storage), it is better than records, since I don't need to pass values on every function call, you can access any table simply by using an ID or Name, but it is still not quite handy to update.
Do we have to face the trouble with CRUD on data structures, or is it that I am not using the correct design principle with Erlang?
P.S. to make this question less abstract, let me illustrate more with my scenario:
In a function call, I may be checking some fields in a "obj" -- which would be a record in Erlang, and modify several other fields of it, so that means I need to assign a lot of temporary variables and return the record with new fields altogether. And this can be really complicated when the record is nested in a list; it is also painful to name a new variable when a field is changed a lot of times.
Best regardsZhiqian
Subject: Re: [erlang-questions] Update with complicated data structure
From: fernando.benavides@REDACTED
Date: Mon, 23 Nov 2015 09:04:03 -0300
CC: erlang-questions@REDACTED
To: on-your-mark@REDACTED
Hi Yuan,
I have proposed two alternatives here. ‘brujo1’ assumes you don’t care about the order of the companies in your company_list. ‘brujo2’ is entirely compatible with your function.
Cheers!
On Nov 23, 2015, at 07:06, YuanZhiqian <on-your-mark@REDACTED> wrote:Hi Guys,
Sorry to bother you again... I am totally a green hand in Erlang :(
Here is the problem I am now struggling with: in C&C++, we are always able to update a field in an object simply using obj.field1 = Value; But in Erlang, since its once-bound-never-change policy, people would have to find a way around to achieve the same goal, and things are getting worse when the data structure is a little more complicated, which is my case:
I have a list of records, whose definition is as follows
-record(company_info, { company_id, budget, consumption, compaign_ids }).
What I want to do is to add a value to the consumption of the record whose company_id is given, and returning error message if there's no such record found. Written in C, that would be:
///////////////////////////////////In C&C++///////////CompanyInfo co_list[1000];/* initialized somewhere else ... */
for (size_t i = 0; i < 1000; ++i) { if (co_list[i].comany_id == co_id) { co_list[i].consumption += price; break; }}
if (i == 1000) err_msg = "bla...";//////////////////////////////////////////////////////
But in Erlang, I couldn't find a straightforward way to do this, my code is like this:
////////////////////////////In Erlang//////////////////////////%Co_list is the list of company_info records
cal_win_notice({Co_id, Ca, Adgrp, Price, Cur}, #state{company_list = Co_list, campaign_list= Ca_list} = State) -> case lists:any(fun(#company_info{company_id = A}) -> A == Co_id end, Co_list) of true -> New_co_list = lists:map(fun(R) -> case R#company_info.company_id of Co_id -> R#company_info{consumption = R#company_info.consumption + Price}; _ -> R end end, Co_list), {ok, State#state{company_list = New_co_list}}; false -> {not_found, State} end.
Well, as shown above, the codes in bold fonts are doing the same logic which in C can be done in just one expression. This will certainly make the code unnecessarily verbose when there are more similar operations to come. What should I do? I think this is due to Erlang's feature, but in case I am wrong and making a simple thing complicated ...
I would appreciate so much with any advises.
Best regardsZhiqian
_______________________________________________erlang-questions mailing listerlang-questions@REDACTED://erlang.org/mailman/listinfo/erlang-questions
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20151124/f661afa4/attachment.htm>
More information about the erlang-questions
mailing list