Discussion:
[erlang-questions] If you are homesick for object.selector
unknown
2013-01-24 01:52:25 UTC
Permalink
We've had a claim recently that using
Person#person_name
instead of
Person.name
is so horrible that it's scaring off people who would otherwise
use Erlang.

What would be _Erlangish_ approach to this look like?
(Apart from implementing frames, of course.)

I think PL/I was the first language to use "." for
field selection. COBOL and Algol 68 used (selector OF record).

In the statement

x = thingy.selector;

what is ".selector"?

It is nothing other than a function, applied to the argument
"thingy" to yield a result.

What's the Erlang syntax for applying a function to an argument?

X = selector(Thingy)

In the statement

thingy.selector = y;

what is ".selector ="?

It is nothing other than a function, applied to two arguments.
What's the Erlang syntax for applying a function to two arguments?

Thingy1 = set_selector(Thingy0, Y)

Now we can define these things manually. We just have to include
a clause for each visible record type.

What's the Erlang way to generate functions automatically from
declarative information?

Use attributes to provide the information and a parse transform
to do the generation.

For example, you might write

-record(person, {id,name,department_id,manager_id,age,job}).
-record(department, {id,name, manager_id}).
-record(project, {id,name,department_id}).
-getters([id,name]).
-setters([name]).

From that, you might like to get automatically generated code like

id({person,F,_,_,_,_,_}) -> F;
id({department,F,_,_}) -> F;
id({project,F,_,_}) -> F.

name({person,_,F,_,_,_,_}) -> F;
name({department,_,F,_}) -> F;
name({project,_,F,_}) -> F.

set_name({person,X1,_,X3,X4,X5,X6}, F) ->
{person,X1,F,X3,X4,X5,X6};
set_name({department,X1,_,X3}, F) ->
{department,X1,F,X3};
set_name({project,X1,_,X3}, F) ->
{project,X1,F,X3}.

Well, as it happens, that code _was_ automatically generated, and
it was automatically generated from those lines. This was just a
quick prototype, so I whipped it up in AWK. Two pages with comments,
one page without. The _right_ way is a parse transform, of course.

I don't regard this design as settled, so there's no EEP.
For example, it's reasonable to want automatically generated -spec
declarations as well, which would generally look like

-spec <field>(#<record 1>{}) -> <field type 1>
; (#<record 2>{}) -> <field type 2>
... .
-spec set_<field>(R, <field type 1>) -> R when R :: #<record 1>{}
; (R, <field type 2>) -> R when R :: #<record 2>{}
... .

but this is tedious rather than difficult.

For another thing, you might want to give the selector function a different
name from the field and you might not want all possible records for some
selector function.

The nice thing is that code generators like this can be written entirely
in Erlang using existing features.
unknown
2013-01-24 02:37:47 UTC
Permalink
Richard,

There is already this:
https://github.com/esl/parse_trans/blob/master/src/exprecs.erl

But I think their point is that Person.name does not require extra
keystrokes to get the value, as opposed to Person#person.name or
person:name(Person).

They're incorrect when claiming it makes things harder, it's just a lot
more tedious, especially if you have a lot of different values to
manipulate. A simple example would be an RPG video game character, which
has various kinds of state, a name, a class, stats, equipped items,
inventory, unlocks, friends, quickchat, options and more. Erlang makes
programming this kind of thing a nightmare, and all that simply because
you can't do something like:

Character.current_weapon.ability.points_req

Or

Character.inventory[0].name

Or at least, not without a lot more keystrokes. And let's not even speak
about actually modifying these values or adding an item to the
inventory. In a language as horrible as PHP, adding an item to the
inventory can be written as:

Character->inventory[] = Item;

You of course have to know what [] means, but it makes the code
incredibly easier to read. Erlang lacks all these easy data manipulation
facilities. I am not sure this can be fully resolved.

Of course, perhaps one could use some Lua behind Erlang to do the game
logic, but that's not really a good selling point for people to use
Erlang, it's at best a compromise.
Post by unknown
We've had a claim recently that using
Person#person_name
instead of
Person.name
is so horrible that it's scaring off people who would otherwise
use Erlang.
What would be _Erlangish_ approach to this look like?
(Apart from implementing frames, of course.)
I think PL/I was the first language to use "." for
field selection. COBOL and Algol 68 used (selector OF record).
In the statement
x = thingy.selector;
what is ".selector"?
It is nothing other than a function, applied to the argument
"thingy" to yield a result.
What's the Erlang syntax for applying a function to an argument?
X = selector(Thingy)
In the statement
thingy.selector = y;
what is ".selector ="?
It is nothing other than a function, applied to two arguments.
What's the Erlang syntax for applying a function to two arguments?
Thingy1 = set_selector(Thingy0, Y)
Now we can define these things manually. We just have to include
a clause for each visible record type.
What's the Erlang way to generate functions automatically from
declarative information?
Use attributes to provide the information and a parse transform
to do the generation.
For example, you might write
-record(person, {id,name,department_id,manager_id,age,job}).
-record(department, {id,name, manager_id}).
-record(project, {id,name,department_id}).
-getters([id,name]).
-setters([name]).
From that, you might like to get automatically generated code like
id({person,F,_,_,_,_,_}) -> F;
id({department,F,_,_}) -> F;
id({project,F,_,_}) -> F.
name({person,_,F,_,_,_,_}) -> F;
name({department,_,F,_}) -> F;
name({project,_,F,_}) -> F.
set_name({person,X1,_,X3,X4,X5,X6}, F) ->
{person,X1,F,X3,X4,X5,X6};
set_name({department,X1,_,X3}, F) ->
{department,X1,F,X3};
set_name({project,X1,_,X3}, F) ->
{project,X1,F,X3}.
Well, as it happens, that code _was_ automatically generated, and
it was automatically generated from those lines. This was just a
quick prototype, so I whipped it up in AWK. Two pages with comments,
one page without. The _right_ way is a parse transform, of course.
I don't regard this design as settled, so there's no EEP.
For example, it's reasonable to want automatically generated -spec
declarations as well, which would generally look like
-spec <field>(#<record 1>{}) -> <field type 1>
; (#<record 2>{}) -> <field type 2>
... .
-spec set_<field>(R, <field type 1>) -> R when R :: #<record 1>{}
; (R, <field type 2>) -> R when R :: #<record 2>{}
... .
but this is tedious rather than difficult.
For another thing, you might want to give the selector function a different
name from the field and you might not want all possible records for some
selector function.
The nice thing is that code generators like this can be written entirely
in Erlang using existing features.
_______________________________________________
erlang-questions mailing list
erlang-questions
http://erlang.org/mailman/listinfo/erlang-questions
--
Lo?c Hoguin
Erlang Cowboy
Nine Nines
http://ninenines.eu
unknown
2013-01-24 09:12:55 UTC
Permalink
An alternative syntax for working with (nested) records is functional
lenses, the downside being evaluated at runtime opposed to a compiled
parse transform solution.
However this does not save you any keystrokes for Obj.selector type expressions.

Taking Lo?c's example:

{Get,Set} = compose([#char.cur_weapon, #weapon.ability, #ability.points_req]),
Character2 = S(123, Character),
123 = G(Character2).

Jesper Louis Andersen wrote a simple Erlang implementation which can
be found here: https://github.com/jlouis/erl-lenses

Olav
Post by unknown
Richard,
https://github.com/esl/parse_trans/blob/master/src/exprecs.erl
But I think their point is that Person.name does not require extra
keystrokes to get the value, as opposed to Person#person.name or
person:name(Person).
They're incorrect when claiming it makes things harder, it's just a lot more
tedious, especially if you have a lot of different values to manipulate. A
simple example would be an RPG video game character, which has various kinds
of state, a name, a class, stats, equipped items, inventory, unlocks,
friends, quickchat, options and more. Erlang makes programming this kind of
Character.current_weapon.ability.points_req
Or
Character.inventory[0].name
Or at least, not without a lot more keystrokes. And let's not even speak
about actually modifying these values or adding an item to the inventory. In
a language as horrible as PHP, adding an item to the inventory can be
Character->inventory[] = Item;
You of course have to know what [] means, but it makes the code incredibly
easier to read. Erlang lacks all these easy data manipulation facilities. I
am not sure this can be fully resolved.
Of course, perhaps one could use some Lua behind Erlang to do the game
logic, but that's not really a good selling point for people to use Erlang,
it's at best a compromise.
Post by unknown
We've had a claim recently that using
Person#person_name
instead of
Person.name
is so horrible that it's scaring off people who would otherwise
use Erlang.
What would be _Erlangish_ approach to this look like?
(Apart from implementing frames, of course.)
I think PL/I was the first language to use "." for
field selection. COBOL and Algol 68 used (selector OF record).
In the statement
x = thingy.selector;
what is ".selector"?
It is nothing other than a function, applied to the argument
"thingy" to yield a result.
What's the Erlang syntax for applying a function to an argument?
X = selector(Thingy)
In the statement
thingy.selector = y;
what is ".selector ="?
It is nothing other than a function, applied to two arguments.
What's the Erlang syntax for applying a function to two arguments?
Thingy1 = set_selector(Thingy0, Y)
Now we can define these things manually. We just have to include
a clause for each visible record type.
What's the Erlang way to generate functions automatically from
declarative information?
Use attributes to provide the information and a parse transform
to do the generation.
For example, you might write
-record(person, {id,name,department_id,manager_id,age,job}).
-record(department, {id,name, manager_id}).
-record(project, {id,name,department_id}).
-getters([id,name]).
-setters([name]).
From that, you might like to get automatically generated code like
id({person,F,_,_,_,_,_}) -> F;
id({department,F,_,_}) -> F;
id({project,F,_,_}) -> F.
name({person,_,F,_,_,_,_}) -> F;
name({department,_,F,_}) -> F;
name({project,_,F,_}) -> F.
set_name({person,X1,_,X3,X4,X5,X6}, F) ->
{person,X1,F,X3,X4,X5,X6};
set_name({department,X1,_,X3}, F) ->
{department,X1,F,X3};
set_name({project,X1,_,X3}, F) ->
{project,X1,F,X3}.
Well, as it happens, that code _was_ automatically generated, and
it was automatically generated from those lines. This was just a
quick prototype, so I whipped it up in AWK. Two pages with comments,
one page without. The _right_ way is a parse transform, of course.
I don't regard this design as settled, so there's no EEP.
For example, it's reasonable to want automatically generated -spec
declarations as well, which would generally look like
-spec <field>(#<record 1>{}) -> <field type 1>
; (#<record 2>{}) -> <field type 2>
... .
-spec set_<field>(R, <field type 1>) -> R when R :: #<record 1>{}
; (R, <field type 2>) -> R when R :: #<record 2>{}
... .
but this is tedious rather than difficult.
For another thing, you might want to give the selector function a different
name from the field and you might not want all possible records for some
selector function.
The nice thing is that code generators like this can be written entirely
in Erlang using existing features.
_______________________________________________
erlang-questions mailing list
erlang-questions
http://erlang.org/mailman/listinfo/erlang-questions
--
Lo?c Hoguin
Erlang Cowboy
Nine Nines
http://ninenines.eu
_______________________________________________
erlang-questions mailing list
erlang-questions
http://erlang.org/mailman/listinfo/erlang-questions
--
Med Vennlig Hilsen
Olav Frengstad

Systemutvikler // FWT
+47 920 42 090
unknown
2013-01-24 20:24:20 UTC
Permalink
Post by unknown
{Get,Set} = compose([#char.cur_weapon, #weapon.ability, #ability.points_req]),
Character2 = S(123, Character),
123 = G(Character2).
Jesper Louis Andersen wrote a simple Erlang implementation which can
be found here: https://github.com/jlouis/erl-lenses
I noticed this was posted on the list quite a while ago, but I missed it then.

I have added lens support in exprecs, with reference in the docs to
Jesper's erl-lenses project:

Eshell V5.9.2 (abort with ^G)
1> test_exprecs:'#lens-'(a,r).
{#Fun<test_exprecs.6.45636860>,
#Fun<test_exprecs.7.45636860>}

2> {G,S} = v(1).
{#Fun<test_exprecs.6.45636860>,
#Fun<test_exprecs.7.45636860>}

3> R = test_exprecs:'#new-r'().
{r,0,0,0}

4> G(S(17,R)).
17

5> S(17,R).
{r,17,0,0}

Pushed to http://github.com:uwiger/parse_trans.git

BR,
Ulf W

Ulf Wiger, Co-founder & Developer Advocate, Feuerlabs Inc.
http://feuerlabs.com
unknown
2013-01-24 12:39:29 UTC
Permalink
Post by unknown
Character.current_weapon.ability.points_req
I think this is the major reason. It allows you to "chain" access to deep data. Note that this is a "projection" operation. You project out an element from the pair. The other solution, which is more Erlang-idiomatic is to match on the object and decode needed fields. But this solution is problematic when you need to access deep object data.

What you really need is composition of lenses, and a neat syntax for doing so. That is a composable access language for obtaining data deep in structures. The usual chaining projection does *not* work in Erlang because you don't know the type of the object at compile time, unless you have the record name to help you. For that to work, you need frames, or something which works the same.

On the other hand, when people access deep data like that, I often become concerned. Why is data not readily available to them but has to be dug up from far below the depths of a structure? Is this the right representation? There is overhead in following pointers and you can't always cache access over function boundaries.


Jesper Louis Andersen
Erlang Solutions Ltd., Copenhagen
unknown
2013-01-24 14:56:00 UTC
Permalink
Post by unknown
Post by unknown
Character.current_weapon.ability.points_req
I think this is the major reason. It allows you to "chain" access to deep data. Note that this is a "projection" operation. You project out an element from the pair. The other solution, which is more Erlang-idiomatic is to match on the object and decode needed fields. But this solution is problematic when you need to access deep object data.
What you really need is composition of lenses, and a neat syntax for doing so. That is a composable access language for obtaining data deep in structures. The usual chaining projection does *not* work in Erlang because you don't know the type of the object at compile time, unless you have the record name to help you. For that to work, you need frames, or something which works the same.
On the other hand, when people access deep data like that, I often become concerned. Why is data not readily available to them but has to be dug up from far below the depths of a structure? Is this the right representation? There is overhead in following pointers and you can't always cache access over function boundaries.
Are you suggesting that #character *duplicates* fields from both #weapon
and #ability? Then you'd just end up with #character having hundreds of
fields, which is as unmanageable and even less readable, especially if
some share a common name, like #character.attack_pts and #weapon.attack_pts.

Hierarchy helps clarity. "Character.current_weapon.ability.points_req"
is the direct transcription of "Character's current weapon's special
ability's required points". (Completely made up, but would apply to
various games I know. Heck it'd be even worse for management games.)

Not talking about pointers there, you don't need them for enabling all this.
--
Lo?c Hoguin
Erlang Cowboy
Nine Nines
http://ninenines.eu
unknown
2013-01-25 09:39:28 UTC
Permalink
Are you suggesting that #character *duplicates* fields from both #weapon and #ability? Then you'd just end up with #character having hundreds of fields, which is as unmanageable and even less readable, especially if some share a common name, like #character.attack_pts and #weapon.attack_pts.
No, I am just looking at how the data will be represented in the heap in memory. Each record is a tuple and you access it by following a reference to another tuple until you have been digging deep down into the structure.

Note that few other functional languages support chained projections.

Jesper Louis Andersen
Erlang Solutions Ltd., Copenhagen
unknown
2013-01-24 14:16:46 UTC
Permalink
Post by unknown
Character.current_weapon.ability.points_req
Or
Character.inventory[0].name
Putting my game programmer hat back on, given a choice I would prefer:

Character weapon ability cost

Where each is an application of a method on the prior or in Erlangy speak:

cost(ability(weapon(Character)))

Where in each function destructs and returns an element of the nested structure. I might for sake of argument want to further name them:

costOf(abilityOf(weaponOf(Character)))

Now in a typical game, weaponOf vectors to the currently selected item from the inventory. AbilityOf vectors off of the currently selected special assigned to the B button / right click slot, and the cost is tied to the level of the character for scaling (if you assume a fixed sized mana pool).

Usually each of these behaviors require implicit knowledge of other state, and would likely make extensive use of get/put in the Character's process dictionary to vector accordingly.

This would imply these structures are best managed in an entirely different manner, where the Character process should memoize the values in a process dictionary, and the interrogation should happen only once upon an equip(Weapon) method.

Same issue goes with inventory. We probably need a weapons manual process that can be interrogated for details based on names. These changes would make it more likely to be a bunch of message sends. To WeaponManual, Inventory, Character, etc.

It would be difficult to justify the dot notation as it wouldn't even remotely resemble how one would structure the message sends.

Dave

-=-=- dave -=-=-
Post by unknown
Character.current_weapon.ability.points_req
Or
Character.inventory[0].name
unknown
2013-01-24 15:18:36 UTC
Permalink
Post by unknown
Post by unknown
Character.current_weapon.ability.points_req
Or
Character.inventory[0].name
Character weapon ability cost
cost(ability(weapon(Character)))
costOf(abilityOf(weaponOf(Character)))
Now in a typical game, weaponOf vectors to the currently selected item from the inventory. AbilityOf vectors off of the currently selected special assigned to the B button / right click slot, and the cost is tied to the level of the character for scaling (if you assume a fixed sized mana pool).
Usually each of these behaviors require implicit knowledge of other state, and would likely make extensive use of get/put in the Character's process dictionary to vector accordingly.
This would imply these structures are best managed in an entirely different manner, where the Character process should memoize the values in a process dictionary, and the interrogation should happen only once upon an equip(Weapon) method.
Same issue goes with inventory. We probably need a weapons manual process that can be interrogated for details based on names. These changes would make it more likely to be a bunch of message sends. To WeaponManual, Inventory, Character, etc.
It would be difficult to justify the dot notation as it wouldn't even remotely resemble how one would structure the message sends.
Process dictionary? Messages? I don't understand.

Assume a variable Character. This variable contains everything about the
character. How do you best access and modify Character? The answer must
not involve the process dictionary, processes or message passing. Today
I have to write each access and modification function. Or I can generate
it, but either way I end up with hundreds of functions in many modules.
Or I could use records, and have one line per sub-record per
modification function I write. That's not *easy* nor *practical*. Easy
and practical is:

Character.weapon.ability.cost

for access, and:

Character.weapon.ability.cost = 123

for modification.

Now I know this isn't the Erlang way, but I'm sure there can be a
solution that allows to write something similar. Frames looked like a
pretty good step in the right direction. Regardless of syntax, I'm sure
we can have something like:

Character2 = Character{weapon{ability{cost=123}}}

Where it would be checked against the proper type, evaluated at runtime,
and return a copy of Character with the requested modifications. This
can work for access, "modification", and pattern match. The user would
be aware that it has runtime costs, but will likely still choose this
because it allows him to actually get the work done. There's many
projects that I wouldn't even dream to do because of how tedious it
would be, as I want to get my project running and not battle endlessly
to modify my data.
--
Lo?c Hoguin
Erlang Cowboy
Nine Nines
http://ninenines.eu
unknown
2013-01-24 16:13:41 UTC
Permalink
Now I know this isn't the Erlang way, but I'm sure there can be a solution
that allows to write something similar. Frames looked like a pretty good
step in the right direction. Regardless of syntax, I'm sure we can have
Character2 = Character{weapon{ability{cost=123}}}
Where it would be checked against the proper type, evaluated at runtime, and
return a copy of Character with the requested modifications. This can work
for access, "modification", and pattern match. The user would be aware that
it has runtime costs, but will likely still choose this because it allows
him to actually get the work done. There's many projects that I wouldn't
even dream to do because of how tedious it would be, as I want to get my
project running and not battle endlessly to modify my data.
Is there any chance we could make the colon operator left-associative?
That way children of Satan could waste precious CPU cycles writing
things like

Cost = Character:weapon():ability():cost()

While laughing maniacally and dancing around a burning pyre of Prolog books
--
Lo?c Hoguin
Erlang Cowboy
Nine Nines
http://ninenines.eu
_______________________________________________
erlang-questions mailing list
erlang-questions
http://erlang.org/mailman/listinfo/erlang-questions
--
Evan Miller
http://www.evanmiller.org/
unknown
2013-01-24 16:36:06 UTC
Permalink
Post by unknown
Is there any chance we could make the colon operator left-associative?
That way children of Satan could waste precious CPU cycles writing
things like
Cost = Character:weapon():ability():cost()
While laughing maniacally and dancing around a burning pyre of Prolog books
I can't help myself thinking you're one of the most dedicated people
working on making the square peg fit the seemingly round hole on this
mailing list :)
unknown
2013-01-24 17:27:15 UTC
Permalink
Post by unknown
Post by unknown
Cost = Character:weapon():ability():cost()
While laughing maniacally and dancing around a burning pyre of Prolog
books
I can't help myself thinking you're one of the most dedicated people
working on making the square peg fit the seemingly round hole on this
mailing list :)
Evan develops one of the most developed and most widely used ORM on Erlang,
so you have to admit that he definitely has success in this complicated
task.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20130124/61769f6c/attachment.html>
unknown
2013-01-24 17:41:35 UTC
Permalink
I'm not making a judgement call on any of it, whether it's worth it or
not or something to aim for, at least not in that post.

It just striked me as somewhat peculiar to ask to change the
associativity of one of the most basic operators of a language to be
able to get something that looks different/shorter to call functions
around following countless arguments on the same topic in the last few
days.

I don't know why making calls chainable that way is *that* desirable, as
I tend to prefer unambiguous (even if verbose) code to optimized code
throughput on a per-character basis, but Evan Miller certainly desires
it a whole damn lot. He's got to make that square peg fit real hard :)

Regards,
Fred
Post by unknown
Post by unknown
Post by unknown
Cost = Character:weapon():ability():cost()
While laughing maniacally and dancing around a burning pyre of Prolog
books
I can't help myself thinking you're one of the most dedicated people
working on making the square peg fit the seemingly round hole on this
mailing list :)
Evan develops one of the most developed and most widely used ORM on Erlang,
so you have to admit that he definitely has success in this complicated
task.
unknown
2013-01-24 20:33:45 UTC
Permalink
It wasn't originally about chainability, was it.

I'd support that one won't usually have deep chains, except when trying things, scripting, also in games. It would indicate something is off.

So the chaining is one thing, but that verbosity, I think it is played down too nonchalantly. It does make programming harder. It would be a serious win to overcome that. I can only suspect that one doesn't see it that much anymore once you are fully used to it but I am positive it would benefit everybody.

Best,
Henning
Post by unknown
I'm not making a judgement call on any of it, whether it's worth it or
not or something to aim for, at least not in that post.
It just striked me as somewhat peculiar to ask to change the
associativity of one of the most basic operators of a language to be
able to get something that looks different/shorter to call functions
around following countless arguments on the same topic in the last few
days.
I don't know why making calls chainable that way is *that* desirable, as
I tend to prefer unambiguous (even if verbose) code to optimized code
throughput on a per-character basis, but Evan Miller certainly desires
it a whole damn lot. He's got to make that square peg fit real hard :)
Regards,
Fred
Post by unknown
Post by unknown
Post by unknown
Cost = Character:weapon():ability():cost()
While laughing maniacally and dancing around a burning pyre of Prolog
books
I can't help myself thinking you're one of the most dedicated people
working on making the square peg fit the seemingly round hole on this
mailing list :)
Evan develops one of the most developed and most widely used ORM on Erlang,
so you have to admit that he definitely has success in this complicated
task.
_______________________________________________
erlang-questions mailing list
erlang-questions
http://erlang.org/mailman/listinfo/erlang-questions
unknown
2013-01-24 21:41:01 UTC
Permalink
It's a definite possibility. I still work in Erlang with no tools at
all past vim and tmux to get a shell right next to it, and tend not to
mind verbosity *if* it makes maintenance and readability simpler, less
ambiguous.

I've always considered myself to be a rather slow programmer, and I
don't especially care about how fast I am at writing code nearly as much
as how fast code can be written so I understand it *correctly* in as
short a time as possible.

That's why I can be in favour of trying to get terse code or compact
representations (pattern matching is the best thing for this), but I
tend to dislike things like overloading existing constructs, which then
force me to understand more and more of the context that surrounds a bit
of code to know what it does. Sometimes the terseness of code ends up
being a pure trade off between speed of writing and speed of
understanding (complex regular expressions compared to writing a little
one-off parser can be a good example of this debate).

Given I'm not having a personal problem understanding most Erlang code
that respects OTP principles, and that understandability comes before
most other factors to me (and I care about my own opinion very much!),
I tend to take ideas such as overloading well-defined semantics for the
sake of terseness as a long term threat to a lot of the things that
make Erlang great to me right now.

I think a lot of people make the implicit choice of pushing more code
faster, thinking "oh it's not gonna be around in 15 years". I think this
gives an unfair advantage to features that improve productivity before
maintainability (when the objectives clash). It's a decision I
frequently make. I sometimes think I should force myself to
take the egotistical position that I know better and don't
want to deal with all the experimental one-off prototypes that ended up
being pushed in production by eager middle-managers as what I want to
end up maintaining in the future.

It's a very hand-wavy position, and I realize there's no moral high
ground, that projects are different and that various developers have
different priorities, capacities to understand an memorize.

I just feel maintainability should be seen as more important than it
is seen in general -- after all, roughly 30% of the programmer time spent
in a project is for development, 70% of the time spent is in maintenance.
Of that 70%, between 50% to 90% of it is spent trying to figure out what
the hell the code is doing (that's 20% to 60% of the whole project's
life!)

With these numbers, it seems insane to optimize for fast writing instead
of fast understanding.

Regards,
Fred.

P.S. That got long and rant-y way faster than I expected! Sorry!
Post by unknown
It wasn't originally about chainability, was it.
I'd support that one won't usually have deep chains, except when trying things, scripting, also in games. It would indicate something is off.
So the chaining is one thing, but that verbosity, I think it is played down too nonchalantly. It does make programming harder. It would be a serious win to overcome that. I can only suspect that one doesn't see it that much anymore once you are fully used to it but I am positive it would benefit everybody.
Best,
Henning
Post by unknown
I'm not making a judgement call on any of it, whether it's worth it or
not or something to aim for, at least not in that post.
It just striked me as somewhat peculiar to ask to change the
associativity of one of the most basic operators of a language to be
able to get something that looks different/shorter to call functions
around following countless arguments on the same topic in the last few
days.
I don't know why making calls chainable that way is *that* desirable, as
I tend to prefer unambiguous (even if verbose) code to optimized code
throughput on a per-character basis, but Evan Miller certainly desires
it a whole damn lot. He's got to make that square peg fit real hard :)
Regards,
Fred
Post by unknown
Post by unknown
Post by unknown
Cost = Character:weapon():ability():cost()
While laughing maniacally and dancing around a burning pyre of Prolog
books
I can't help myself thinking you're one of the most dedicated people
working on making the square peg fit the seemingly round hole on this
mailing list :)
Evan develops one of the most developed and most widely used ORM on Erlang,
so you have to admit that he definitely has success in this complicated
task.
_______________________________________________
erlang-questions mailing list
erlang-questions
http://erlang.org/mailman/listinfo/erlang-questions
unknown
2013-01-24 22:57:01 UTC
Permalink
Post by unknown
I just feel maintainability should be seen as more important than it
is seen in general -- after all, roughly 30% of the programmer time spent
in a project is for development, 70% of the time spent is in maintenance.
Of that 70%, between 50% to 90% of it is spent trying to figure out what
the hell the code is doing (that's 20% to 60% of the whole project's
life!)
With these numbers, it seems insane to optimize for fast writing instead
of fast understanding.
"These numbers" are not physical constants. They depend solely on your
market and on your development strategy. Other people's numbers will
be quite different, and in many contexts, optimizing for fast writing
can be quite sane.

There's an apocryphal story of Andrew Carnegie visiting a British
steel manufacturer. The manufacturer boasted that with proper care and
maintenance, some of his furnaces had been in service for decades.

"And that," Carnegie replied, "is why the United States is making you
a back number. You're using still furnaces that ought to have been
scrapped twenty years ago."

I bring this up to point out that there are two approaches to
maintenance. One can build something that is high-quality and lasts
for a long time with proper ongoing investment (what I'll call the
"British" approach), or one can build on the cheap and when it breaks,
crank out a replacement (what I'll call the "American" approach).

It's tempting to think that the British approach is more "long-term",
and there is a strong tendency among engineers to equate build quality
with moral virtue, but there is significant a long-term economic
advantage to the American approach: if you're constantly building from
scratch, you end up taking advantage of technological advances that
are more difficult for your "British" counterparts to incorporate into
their older designs.

DeTocqueville has a similar analysis of the American versus British
shipping industries in the early 1800s. Americans treated ships as
expendable, the British didn't, and the Americans ended up dominating
the industry. The average ship in an American merchant fleet was worse
in terms of quality, but it was newer in terms of design, so it tended
to reach its destination more quickly. (Of course, it was more likely
to be shipwrecked along the way, and hence American seamen were
better-paid than their British counterparts; but the additional wages
were easily furnished by the market's thirst for fast trans-Atlantic
shipping.)

I think there are lessons here for software. Even if *technology*
itself doesn't change (and it does), *markets* change swiftly, and it
can be necessary to build new versions of products rapidly (call it
"iterating" or "pivoting" or whatever you want). Engineers tend to
care deeply about quality-of-build and maintainability, but in some
sectors it is much more practical to be constantly building and
rebuilding "crap" in short time frames. I think this insight largely
explains the popularity of Ruby on Rails. It might seem insane, but
it's really just economics.

Evan
unknown
2013-01-25 00:42:13 UTC
Permalink
There is a difference between maintaining to a functional level and
maintaining in order to keep it current with demands and needs.

The usefulness of a program through time comes from its ability to
answer customer demands and needs -- these needs evolve and change as
the application is being used and has an impact on its environment. It
doesn't live in a vacuum.

The thing is, as you force a program to evolve, you add to its entropy
and it keeps getting higher until it's no longer managable, unless it's
taken care of. That includes bugfixes, but also all the improvement you
could write a new app for. It is not always economically viable to throw
it all out and start from scratch, the same way itsn't always
economically viable to maintain piles of garbage.

Properly maintainable apps are more like factories where if you haven't
welded your furnaces to the support beams, you'll be able to replace them
without taking the whole damn structure down or even stopping
production at all. Sometimes the models will change so much you'll have
no choice but to build a new complex to host them. Doesn't mean all
furnace upgrades or changes warrant a new building.

The problem with code is that there is often no up-to-date
documentation, no owner for the code, it's full of hidden features,
or bugs accepted as features, work-arounds that are implicit but not
documented or specified anywhere, and so on.

To be able to replace any of this code with anything else and have
something at least functionally equivalent, you have to be able to
reverse engineer it. The decision to throw shit out is economical by
nature, but a large part of the price is how much of a brainfuck it will
be to do the desired updates.

When the code is impossible to understand, or that understanding it takes
too long, then it makes sense to throw it all away. It's often more
economical to figure things out as you go without needing to care for
old interfaces that have non-obvious uses slowing you down. It's also
more fun too!

If you can understand the app easily, see the patterns in it, how to
refactor it, and get a good understanding of its structure, it should be
possible to throw away all the old legacy code, and get to write
100% new code in an otherwise old application. And it would be obtained at
a good cost, because answering that user's need was doable efficiently
without them needing to pay for the full reimplementation as part of the
deal.

What I want to aim for, generally speaking, is the case where code is
understandable enough that it never makes sense to throw all of it away.
Just the outdated parts of it, one at a time, as needs grow.

I've discussed of points related to that before, on former discussions
we had with parametrized modules, models, and the structure of web
frameworks. I don't think we need to end up agreeing in any case. I get
your point and you hopefully get mine -- we just choose a different
angle of attack in how we'd do things, I think. I can't have the
audacity to assert my way is the best way; at most, it's the one I
prefer.

Regards,
Fred.
Post by unknown
Post by unknown
I just feel maintainability should be seen as more important than it
is seen in general -- after all, roughly 30% of the programmer time spent
in a project is for development, 70% of the time spent is in maintenance.
Of that 70%, between 50% to 90% of it is spent trying to figure out what
the hell the code is doing (that's 20% to 60% of the whole project's
life!)
With these numbers, it seems insane to optimize for fast writing instead
of fast understanding.
"These numbers" are not physical constants. They depend solely on your
market and on your development strategy. Other people's numbers will
be quite different, and in many contexts, optimizing for fast writing
can be quite sane.
There's an apocryphal story of Andrew Carnegie visiting a British
steel manufacturer. The manufacturer boasted that with proper care and
maintenance, some of his furnaces had been in service for decades.
"And that," Carnegie replied, "is why the United States is making you
a back number. You're using still furnaces that ought to have been
scrapped twenty years ago."
I bring this up to point out that there are two approaches to
maintenance. One can build something that is high-quality and lasts
for a long time with proper ongoing investment (what I'll call the
"British" approach), or one can build on the cheap and when it breaks,
crank out a replacement (what I'll call the "American" approach).
It's tempting to think that the British approach is more "long-term",
and there is a strong tendency among engineers to equate build quality
with moral virtue, but there is significant a long-term economic
advantage to the American approach: if you're constantly building from
scratch, you end up taking advantage of technological advances that
are more difficult for your "British" counterparts to incorporate into
their older designs.
DeTocqueville has a similar analysis of the American versus British
shipping industries in the early 1800s. Americans treated ships as
expendable, the British didn't, and the Americans ended up dominating
the industry. The average ship in an American merchant fleet was worse
in terms of quality, but it was newer in terms of design, so it tended
to reach its destination more quickly. (Of course, it was more likely
to be shipwrecked along the way, and hence American seamen were
better-paid than their British counterparts; but the additional wages
were easily furnished by the market's thirst for fast trans-Atlantic
shipping.)
I think there are lessons here for software. Even if *technology*
itself doesn't change (and it does), *markets* change swiftly, and it
can be necessary to build new versions of products rapidly (call it
"iterating" or "pivoting" or whatever you want). Engineers tend to
care deeply about quality-of-build and maintainability, but in some
sectors it is much more practical to be constantly building and
rebuilding "crap" in short time frames. I think this insight largely
explains the popularity of Ruby on Rails. It might seem insane, but
it's really just economics.
Evan
unknown
2013-01-25 12:33:39 UTC
Permalink
Post by unknown
Assume a variable Character. This variable contains everything about the
character. How do you best access and modify Character? The answer must not
involve the process dictionary, processes or message passing. Today I have
to write each access and modification function. Or I can generate it, but
either way I end up with hundreds of functions in many modules.
Assuming that "you're doing it wrong" and you make "doing this wrong" a
requirement, the easiest way is nested proplists (as would effectively be
the case in Perl, Python, Ruby, Javascript, Lua, etc. minus some fine
points of the implementations of the dictionaries, hashes, and tables), and
two utility functions:

of(Object,Property) -> proplists:get_value(Property,Object).

has(Object,Property,Value) -> [ { Property, Value } |
proplists:delete(Property,Object) ].

Where due to the horrible nature of the beast Character.weapon.ability.cost
is:

of(of(of(Character,weapon),ability),cost).

And the assignment Character.weapon.ability.cost := 123 is:

Character2 = has(Character,weapon, has(of(Character,weapon), ability),
has(of(of(Character,weapon),ability), cost, 123))).

Which of course once again only goes to suggest "you're doing it wrong",
but at least you aren't writing reams of code for each object type. This
would then lend itself to abstracting out each "type" of setting if you
want to feel like you're doing something "object oriented":

character:wield(Character,Weapon ) ->
has(Character,weapon,Weapon).

weapon:enchanted(Weapon,Ability) ->
has(Weapon,ability, Ability).

ability:price(Ability,Cost) ->
has(Ability,cost,Cost).

Which would disguise your problem into something more "object oriented":

Character2 =
character:wield(Character,
weapon:enchanted(of(Character,weapon),ability:price(of(of(Character,weapon),ability),123))).

But the entire notion of nested structures for this sort of design would be
wrong in most languages as the exact semantics rely upon wether or not you
are intending for just this instance of this Character's weapon's ability's
cost to be modified, or you are modifying the cost of the ability across
the game (due to ability being a reference to a shared data structure, or
just intending all instances of this weapon to be modified (due to ability
being a substructure of weapon itself AND weapon is a reference to a shared
structure).

In either of those two cases, this approach will fail entirely, as it will
construct clean proplists and only modify the cost of this specific
character's individual weapon's specific ability cost. So once again:

Character.weapon.ability.cost = 123

Is very difficult to qualify within your assumptions, because we don't know
the structural ramifications of the . operator.

Part of the reason I brought up process dictionaries and processes is I've
been playing around with structuring game data using them:

https://github.com/cthulhuology/eoom/blob/master/object.erl

Where you can send "objects" messages to do these things:

1> l(object).
{module,object}
2> O = object:new().
<0.34.0>
3> O ! [ self(), does, hello, fun() -> io:format("hello world~n") end ].
[<0.31.0>,does,hello,#Fun<erl_eval.20.111823515>]
4> O ! hello.
hello world
hello
5>

The fun thing here is sending funs to objects living out in the servers and
modifying their behavior at a distance. So in this scheme, I would tend to
do something like:

Character ! [ self(), wielding ].

Which would respond with a message send of its own

Sender ! [ wielding, get(weapon) ].

In the interrogating process's wielding method I'd then send the Weapon:

Weapon ! [ self(), price, 123 ].

And it would set its own cost in it's price method.

So there's a lot of ways to skin this cat based on the structure of how you
hide your properties.

Dave
--
-=-=-=-=-=-=-=-=-=-=- http://blog.dloh.org/
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20130125/6b453442/attachment.html>
unknown
2013-01-25 12:56:37 UTC
Permalink
On Thu, Jan 24, 2013 at 10:18 AM, Lo?c Hoguin <essen
Assume a variable Character. This variable contains everything about
the character. How do you best access and modify Character? The
answer must not involve the process dictionary, processes or message
passing. Today I have to write each access and modification
function. Or I can generate it, but either way I end up with
hundreds of functions in many modules.
Assuming that "you're doing it wrong" and you make "doing this wrong" a
Am I? What is the right way then? Creating many processes isn't helping
write my snippets any easier in Erlang, it just complicates things.
the easiest way is nested proplists
Nope, it's still a pain to update.
I don't want to do something object oriented. I hate OO. I just want
primitives to easily update deep data structures.

[...]
But the entire notion of nested structures for this sort of design would
be wrong in most languages as the exact semantics rely upon wether or
not you are intending for just this instance of this Character's
weapon's ability's cost to be modified, or you are modifying the cost of
the ability across the game (due to ability being a reference to a
shared data structure, or just intending all instances of this weapon to
be modified (due to ability being a substructure of weapon itself AND
weapon is a reference to a shared structure).
In either of those two cases, this approach will fail entirely, as it
will construct clean proplists and only modify the cost of this specific
character's individual weapon's specific ability cost.
But modifying the cost of this specific character's individual weapon is
exactly what we want! And it's exactly what is painfully hard to write
in Erlang.
Is very difficult to qualify within your assumptions, because we don't
know the structural ramifications of the . operator.
Think of it as C structs and arrays for example. If I have a field in a
struct in an array in a struct, and I want to update this field's value,
it's a one liner in C, and many many lines in Erlang. Of course Erlang
has immutable variables, but that doesn't prevent it to figure out at
runtime what exactly we want to modify and return a copy of the struct
with the field modified. This of course has a runtime cost, but it's
irrelevant compared to how nicely small your program becomes and how
fast you can write it.
So there's a lot of ways to skin this cat based on the structure of how
you hide your properties.
This isn't about hiding the properties, this is about the syntax for
modifying these properties in the process where you hide them.
--
Lo?c Hoguin
Erlang Cowboy
Nine Nines
http://ninenines.eu
unknown
2013-01-26 02:41:54 UTC
Permalink
Post by unknown
of(Object,Property) -> proplists:get_value(Property,Object).
...
Post by unknown
of(of(of(Character,weapon),ability),cost).
At this point it might be useful to mention R (or rather the S
language that R implements). Leaving S4 objects to one side as
a distraction, S "objects" are immutable. The rule in S is that

f(e1, e2) <- e0

is syntactic sugar for

e1 <- 'f<-'(e1, e2, e0)

with the rule applied recursively (although I've never seen the
details made clear). Even

a[i] <- x

is just shorthand for

a <- '[<-'(a, i, x).

Imagine Erlang to be extended with a := operator with
the following semantics:

var := expr

if var is not bound in the current path, var = expr
if var is bound, introduce a new variable var', var' = expr,
and use var' instead of var downstream
At if/case/receive/... termini, reconcile live variables
as with a SSA phi-function

f(E1,...,En) := E0

rewrite as E1 := 'f:='(E1, ..., En, En)

const := expr

illegal

This would in no way affect the underlying 'no mutable data'/
single assignment nature of Erlang. Indeed, the VM would not
be altered in even the slightest way. It's all compile time.
Then you could write

of(of(of(Character,weapon),ability),cost) := 123

This requires a function 'of:='(Thing, Slot, New_Value).

You could also define

cost(X) -> of(X, cost).
'cost:='(X, C) -> 'of:='(X, cost, C).
...

cost(ability(weapon(Character)) := 123

It's all just pure values and functions underneath.
Would _this_ satisfy the complaints?
unknown
2013-01-27 18:26:53 UTC
Permalink
-=-=- dave -=-=-
Post by unknown
It's all just pure values and functions underneath.
Would _this_ satisfy the complaints?
Well I don't actually have a complaint, although that sugar looks sugary :)

I do, however, see a fundamental design flaw in any Erlang program that attempts to manipulate nested data structures as it were C (or substitute your favorite Algol in Funny Hats here).

Erlang has a wonderful dictionary object for each process, and you can straight forwardly map any Algol in funny hats language solution to Erlang message sends + process dictionaries. You just have to observe strict message passing OO requirements, as process dictionaries can not be modified externally (without playing games at the VM level).

In my experience 100k+ processes acting as basically Python dictionaries or Perl hashes is just as manageable as 100k+ objects in any OO language. Only in Erlang, I can't cheat and those 100k processes are much easier to wrangle over a distributed cluster.

Dave
unknown
2013-01-25 00:31:25 UTC
Permalink
But I think their point is that Person.name does not require extra keystrokes to get the value, as opposed to Person#person.name or person:name(Person).
I thought the complaint was that Person#person.name is not polymorphic;
my point was that name(Person) _can_ be polymorphic, if you seriously
want it to be.
Character.current_weapon.ability.points_req
Or
Character.inventory[0].name
Don't OO programming courses teach "The Law Of Demeter"
(http://en.wikipedia.org/wiki/Law_of_Demeter) any more?
(It's also known as 'don't talk to strangers': send
messages to yourself, your instance variables, and the
parameters and local variables of the current method.)

This particular example is actually a good illustration
of what can go wrong: "ability" is not a property,
it is a property relating a character to a category of
weapons. If one character drops a weapon and another
picks it up, the second player should not acquire the
first player's ability. So it should be something
like
(player abilityWith: (player currentWeaponCategory))
and then points are required to do something, so it _really_
should be something like
(player pointsRequiredTo: #fightOrcs
using: player currentWeaponCategory)
and note that it's
player currentWeaponCategory
not player currentWeapon category
because the player might not _have_ a currentWeapon.
Or at least, not without a lot more keystrokes.
If you're worried about keystrokes, it's DSL time.
Character->inventory[] = Item;
That is *precisely* one of the things that makes it a truly horrible
language. "Don't let strangers touch your private parts." An object
such as a character *must* remain in charge of what happens to its
components (such as an inventory) because otherwise you are not doing
OO programming, you are just hacking around in the dark. The OO way
to add an item to a character's inventory is to *ask the character to
do it*, so the right way to do that is

character addToInventory: item

If you let things like Character->inventory[] = Item happen, you
_also_ let random bits of code reorder your inventory, delete
things from your inventory, and add things from your inventory
to another player's inventory without withdrawing them from
yours.

If Erlang turns people away because it doesn't let people write code
like that, then it's turning away people I am desperately keen to see
NOT touching any code that can affect my life.

Just now there is a seriously broken piece of software affecting
many lives in New Zealand. It's called Novopay (Google it!) and
it is the payroll system for all school-teachers and support staff
in this country. It's overpaying some people, underpaying more,
and not paying others at all. The last time I looked at their
admitted defects web site, one of their forms had refused to accept
the entry of apostrophes in people's names. Well, nobody expects a
large system to work correctly first time; that's why you roll it
out gradually (except the government didn't choose to do that) and
why you keep the old system on hot standby so you can roll back to
something that (now, after long effort) works quickly when it
turns out that people aren't getting paid (except the Government
chose not to do that either and say it is now impossible to go back).
I hereby make two retrodictions:
(a) The designers did not try to follow the Law of Demeter.
(I will give NZ$20 to a local school if I am wrong.)
(b) The critical aspects of the code (dealing with a lot of
different kinds of contracts) were not developed using an
embedded domain specific language.
(Again I will give NZ$20 to a local school if I am wrong.)
You of course have to know what [] means, but it makes the code incredibly easier to read.
I'm not at all sure that I believe it at all.

What you are talking about is ease of writing *low level* code.
Not "small scale". "Low level". The kind of stuff you DON'T want
to make easy to read, but next to invisible. In fact, the kind of
stuff you don't want to write at all, because if you didn't write
it, you didn't wrong it.

One of several enlightening experiences I've had was being in the same
room with a real Haskell expert who was finding some code starting
to get messy. He thought for a couple of minutes, and said

"I'll just define a combinator for that."

Shortly afterwards, his code was markedly smaller and a lot closer
to doing what he wanted. He wasn't making the low level data
structure manipulation easier to read, he was making it NOT THERE
in the source code.

I've read Apple's Key-Value Coding manual, and as I remarked earlier
this week, I've implemented something close to it in my Smalltalk
system. However, there's one "feature" I chose _not_ to imitate:
if you try to use a selector, and there is no method by that name,
but there _is_ an instance variable, KVC will give you direct
access to that variable. You can switch that off, on a per-class
basis, but it's on by default. What this means is that _unless_
you have been careful to switch that feature off in every class
you have, using KVC voids *every* guarantee your classes want to
offer.

Let's face it, trying to follow the Law of Demeter is hard.
It means taking encapsulation and system integrity _seriously_.
It means that when something is awkward to say, you DON'T just
smash-and-grab, you redesign. It means that you try to provide
conceptual-level interfaces.
Erlang lacks all these easy data manipulation facilities. I am not sure this can be fully resolved.
Of course, perhaps one could use some Lua behind Erlang to do the game logic, but that's not really a good selling point for people to use Erlang, it's at best a compromise.
That's completely back to front.

You don't want *more* low-level code in your program,
you want *less*. You devise a DSL in which the things
you need to say about the game logic are easy to say and
many of the mistakes you want to avoid cannot be
expressed and where the data structure manipulation is
just plain NOT THERE in the source code. It's in the
translation of the source code.

And it doesn't matter whether the low level code is going
to be in Erlang or Ada or Lua or F#. You *still* want to
write your game logic at the highest level of abstraction
you are comfortable with hiding as much data structure
manipulation as you can.

Now, a DSL can be an embedded DSL, in which you have the
facilities of the host language as well as the DSL ones.
The DSL might even be a module or two just providing
some handy functions. Basically, that's the Smalltalk/
Law of Demeter approach.
character addToInventory: item
is domain-specific code. It talks about characters, and
items, and inventories, and says NOTHING about the data
structures representing them. The inventory could be an
SQLite table. It could be a concurrent process. It
could be a hash table. And this is where it gets really
nice: if you turn your game into a MPORPG where game
state is replicated and changes have to be broadcast,
your code that works at this level does not need to be
changed.

However, while the EDSL approach makes it _possible_ for
your game logic to be written at a high level, it need
not _prevent_ low level details (alias future bugs)
creeping into that logic. And the checks the compiler
can do are still almost exclusively the checks the
compiler knows how to do for the host language.

A free-standing DSL lets you provide *concept-level*
consistency checks, which is a thing well worth having.


Sorry about the rant, but for reasons I'll spare you I
didn't get any sleep last night and I am just so _tired_
of people wanting to write code they should be running
away from.
unknown
2013-01-25 02:08:36 UTC
Permalink
Post by unknown
But I think their point is that Person.name does not require extra keystrokes to get the value, as opposed to Person#person.name or person:name(Person).
I thought the complaint was that Person#person.name is not polymorphic;
my point was that name(Person) _can_ be polymorphic, if you seriously
want it to be.
It's about ease of use, reducing the extra steps (or plane flight in the
case of Erlang) to get the work done.
Post by unknown
Character.current_weapon.ability.points_req
Or
Character.inventory[0].name
Don't OO programming courses teach "The Law Of Demeter"
(http://en.wikipedia.org/wiki/Law_of_Demeter) any more?
(It's also known as 'don't talk to strangers': send
messages to yourself, your instance variables, and the
parameters and local variables of the current method.)
This particular example is actually a good illustration
of what can go wrong: "ability" is not a property,
it is a property relating a character to a category of
weapons. If one character drops a weapon and another
picks it up, the second player should not acquire the
first player's ability. So it should be something
like
(player abilityWith: (player currentWeaponCategory))
and then points are required to do something, so it _really_
should be something like
(player pointsRequiredTo: #fightOrcs
using: player currentWeaponCategory)
and note that it's
player currentWeaponCategory
not player currentWeapon category
because the player might not _have_ a currentWeapon.
You should play more games. Some recent games (actually probably games
from these past 20 years or more, though it's been quite refined)
feature weapons that can be upgraded. They also feature weapons that
have abilities. Not the character, the weapon itself. For example a
shotgun could have a spread damage ability that you can unlock if you
spend enough points. You can probably guess that giving another
character this weapon would be pretty lame if the weapon's upgrades
didn't stick. Especially in the context of online games where selling
items is fairly common.
Post by unknown
Or at least, not without a lot more keystrokes.
If you're worried about keystrokes, it's DSL time.
Sure. Then Erlang needs that DSL.
Post by unknown
Character->inventory[] = Item;
That is *precisely* one of the things that makes it a truly horrible
language. "Don't let strangers touch your private parts." An object
such as a character *must* remain in charge of what happens to its
components (such as an inventory) because otherwise you are not doing
OO programming, you are just hacking around in the dark. The OO way
to add an item to a character's inventory is to *ask the character to
do it*, so the right way to do that is
character addToInventory: item
Let me stop you right there. Nobody said anything could change
Character. In Erlang it would quite naturally belong to a gen_server and
you'd make calls like {add_item, Item} and let the gen_server handle it.
You'd of course program the gen_server to handle any needed logic (like
inventory full).

The problem is that in Erlang, if I were to use records for example, I
would have to take the inventory from the #character record, add the
item in it, and then put it back in the #character record. This sounds
bearable, you'll probably say. Now imagine if the character could have
one or more sidekick avatars (like, say, a dog and a cat), and you want
to add the item to your first sidekick's inventory. This is PHP:

Character->avatars[0]->inventory[] = Item;

In Erlang, I'd have to update two records and two lists, which would
take quite many lines. Erlang should allow us to focus on the game
logic, not on trying to avoid mistakes while updating data structures.
Post by unknown
If you let things like Character->inventory[] = Item happen, you
_also_ let random bits of code reorder your inventory, delete
things from your inventory, and add things from your inventory
to another player's inventory without withdrawing them from
yours.
Irrelevant as explained above. This doesn't prevent transactional
behavior, you just have to wrap it in a gen_server *like everything else*.
Post by unknown
You of course have to know what [] means, but it makes the code incredibly easier to read.
I'm not at all sure that I believe it at all.
What you are talking about is ease of writing *low level* code.
Not "small scale". "Low level". The kind of stuff you DON'T want
to make easy to read, but next to invisible. In fact, the kind of
stuff you don't want to write at all, because if you didn't write
it, you didn't wrong it.
To reuse your terms, right now, in Erlang, you don't have low level. You
have basement level. You have to change every single element in a
hierarchy one by one and then build it back together. OR generate code
to do that (and hope that code doesn't have bugs). OR write all that
logic in Lua and reduce the size of the code and the potential number of
bugs in it by 3.
Post by unknown
One of several enlightening experiences I've had was being in the same
room with a real Haskell expert who was finding some code starting
to get messy. He thought for a couple of minutes, and said
"I'll just define a combinator for that."
Shortly afterwards, his code was markedly smaller and a lot closer
to doing what he wanted. He wasn't making the low level data
structure manipulation easier to read, he was making it NOT THERE
in the source code.
Of course it was there. He had to define the combinator.

[snip more irrelevant demeter stuff]
Post by unknown
Erlang lacks all these easy data manipulation facilities. I am not sure this can be fully resolved.
Of course, perhaps one could use some Lua behind Erlang to do the game logic, but that's not really a good selling point for people to use Erlang, it's at best a compromise.
That's completely back to front.
You don't want *more* low-level code in your program,
you want *less*. You devise a DSL in which the things
you need to say about the game logic are easy to say and
many of the mistakes you want to avoid cannot be
expressed and where the data structure manipulation is
just plain NOT THERE in the source code. It's in the
translation of the source code.
Of course I want less low-level code in my program. That's why I want to
be able to update data structures in one line instead of five.
Post by unknown
And it doesn't matter whether the low level code is going
to be in Erlang or Ada or Lua or F#. You *still* want to
write your game logic at the highest level of abstraction
you are comfortable with hiding as much data structure
manipulation as you can.
Now, a DSL can be an embedded DSL, in which you have the
facilities of the host language as well as the DSL ones.
The DSL might even be a module or two just providing
some handy functions. Basically, that's the Smalltalk/
Law of Demeter approach.
character addToInventory: item
is domain-specific code. It talks about characters, and
items, and inventories, and says NOTHING about the data
structures representing them. The inventory could be an
SQLite table. It could be a concurrent process. It
could be a hash table. And this is where it gets really
nice: if you turn your game into a MPORPG where game
state is replicated and changes have to be broadcast,
your code that works at this level does not need to be
changed.
However, while the EDSL approach makes it _possible_ for
your game logic to be written at a high level, it need
not _prevent_ low level details (alias future bugs)
creeping into that logic. And the checks the compiler
can do are still almost exclusively the checks the
compiler knows how to do for the host language.
A free-standing DSL lets you provide *concept-level*
consistency checks, which is a thing well worth having.
Sure. And who has to write the code for addToInventory? Someone does.
It'd typically check you have space left in your inventory, and if the
item is stackable and you already have a stack of them in it, increment
by 1 the stack, otherwise add the item. And to add the item I need to
update one and more record and one and more list, which takes quite a
few lines.

Who writes this? Because that's the part that's problematic in Erlang.
Not putting things behind a gen_server or a module or a DSL.
Post by unknown
Sorry about the rant, but for reasons I'll spare you I
didn't get any sleep last night and I am just so _tired_
of people wanting to write code they should be running
away from.
I think you should go take a nap.
--
Lo?c Hoguin
Erlang Cowboy
Nine Nines
http://ninenines.eu
unknown
2013-01-25 03:09:36 UTC
Permalink
Post by unknown
But I think their point is that Person.name does not require extra keystrokes to get the value, as opposed to Person#person.name or person:name(Person).
I thought the complaint was that Person#person.name is not polymorphic;
my point was that name(Person) _can_ be polymorphic, if you seriously
want it to be.
It's about ease of use, reducing the extra steps (or plane flight in the case of Erlang) to get the work done.
(1) Please let's have a real concrete example of about 1 page,
not imaginary one-liners, with names that turn out to be
not as intention-revealing as they look.

(2) Person#person.name is just a field selector; it can only fetch
a stored data. The "frames" analogue, Person~name, has the
same basic property. The Smalltalk analogue, person name,
or the C# analogue, person.name, can run arbitrary code, which
is much more powerful.

Are we debating whether Person~name, with the same fundamental
limitation as field access in C or Java or ML, is a really big
improvement over Person#person_name?

Or has the idea crept in that Person.name might run complex code?

I note that www.missioncriticalit.com claim to be able to generate
about 90% of the code in a business system (in Java, C#, or Mercury)
from semantic models.

That's _really_ where I think the big gains are going to come from.
And I expect the core Erlang ideas to be good for such systems even
if the Erlang language is replaced by a different embodiment of them.

(It should be clear, but if not: each Domain needs its own Domain
Specific Language. "Then Erlang needs that DSL." doesn't really
make sense. 'Then Erlang needs its own toolkit to make building
good DSLs easy' does make sense and I think it's true.
Post by unknown
character addToInventory: item
Let me stop you right there. Nobody said anything could change Character.
And where does that line of code say anything _does_ change Character?
The _association_ between 'character' and 'item' changes, somehow.
That doesn't mean 'character' has to change.

That's the point, really.
unknown
2013-01-25 11:10:07 UTC
Permalink
Post by unknown
Post by unknown
But I think their point is that Person.name does not require extra keystrokes to get the value, as opposed to Person#person.name or person:name(Person).
I thought the complaint was that Person#person.name is not polymorphic;
my point was that name(Person) _can_ be polymorphic, if you seriously
want it to be.
It's about ease of use, reducing the extra steps (or plane flight in the case of Erlang) to get the work done.
(1) Please let's have a real concrete example of about 1 page,
not imaginary one-liners, with names that turn out to be
not as intention-revealing as they look.
It's a real concrete example. I'm sure you can imagine other examples.
Or perhaps you are going to tell me you never had to manage big amounts
of related data in Erlang? (Wouldn't surprise me.)
Post by unknown
(2) Person#person.name is just a field selector; it can only fetch
a stored data. The "frames" analogue, Person~name, has the
same basic property. The Smalltalk analogue, person name,
or the C# analogue, person.name, can run arbitrary code, which
is much more powerful.
Are we debating whether Person~name, with the same fundamental
limitation as field access in C or Java or ML, is a really big
improvement over Person#person_name?
Or has the idea crept in that Person.name might run complex code?
*Data*. Not code. Access. Update. That's all that's needed.
Post by unknown
I note that www.missioncriticalit.com claim to be able to generate
about 90% of the code in a business system (in Java, C#, or Mercury)
from semantic models.
That's _really_ where I think the big gains are going to come from.
And I expect the core Erlang ideas to be good for such systems even
if the Erlang language is replaced by a different embodiment of them.
(It should be clear, but if not: each Domain needs its own Domain
Specific Language. "Then Erlang needs that DSL." doesn't really
make sense. 'Then Erlang needs its own toolkit to make building
good DSLs easy' does make sense and I think it's true.
Let me tell you something about yourself.

You are confronted with the problem of wasting a lot of time writing
basement level code to access and update deep values. You think "Great!
I can write DSL or combinators to solve this!". Now you got two
problems, and you haven't come any closer to solving the first one. The
DSL still maps to functions which needs to access and update these
values, and that code is still painful to write. Your next step is to
think "Great! Let's generate all that code then!". Now you got three
problems, and you better hope to have not made any error when writing
that code generator or you'll waste a lot more time. Speaking of time,
by the time you get to that point the PHP developer has already long
finished his bug-free implementation of the same code and is moving on
to other tasks.

There's absolutely no need for a DSL. All you have to do is have the
correct interface, like character:add_to_inventory(Item, Character) and
your game logic is clear. The problem is that the code on the other side
of this interface is messy, prone to errors and takes too damn long to
write with current Erlang, because Erlang focuses so much on functions
that it totally forgot that in the end it's all about data and it'd be
nice to actually do something meaningful with it.
Post by unknown
Post by unknown
character addToInventory: item
Let me stop you right there. Nobody said anything could change Character.
And where does that line of code say anything _does_ change Character?
The _association_ between 'character' and 'item' changes, somehow.
That doesn't mean 'character' has to change.
That's the point, really.
That's still besides the point. If it's not Character.inventory it's
State.character and State.inventory. Doesn't make updating any easier.
--
Lo?c Hoguin
Erlang Cowboy
Nine Nines
http://ninenines.eu
unknown
2013-01-25 12:25:40 UTC
Permalink
Post by unknown
Let me tell you something about yourself.
I have been told this bit can be considered offensive in English, it
isn't meant to be.
--
Lo?c Hoguin
Erlang Cowboy
Nine Nines
http://ninenines.eu
unknown
2013-01-25 13:07:34 UTC
Permalink
Hi guys,

There is a problem here. Any reasonably sized or structured erlang
application
requires records, despite the grody record syntax. The alternative? Big
hairy unstructured
clods of tuple and lists and things? Worse. Unmaintainable in and of
itself. Hard to pattern
match. Had to manipulate. Hard for humans to grok whilst reading without
squinting your
brain hard and quizzically at the terminal ...

Unlike the matrix, it's not blonde, brunette or a redhead ... It's
something else! ;(

So they're needed? Yes. Use by choice? No. And that's the problem.

I secretly hope for for something better to come along. A big gnarly
unstructured
and frequently accessed tuple would be fine, for example, if there was some
kind
of tuple path expression language... like XML has XPath? Jackpot.

So maybe frames aren't needed at all. Maybe frames would be nice. Perhaps we
just want to reach out and touch the a subset of tuples of lists of tuples
of lists of
tuples of ... I'm pretty sure with or without frames that solves 80% of the
need for me.

The other 20%? - Native support for Kaysian transforms and other natural
conveniences
for efficient slicing, dicing, filtering and merging.

I'm not sure record or any other syntax is actually the problem.

Also, the nice thing about adding something like an XPath like thing for
tuples?
It doesn't break existing applications. It's backward compatible. It's
forward
migratable. No new syntax because an expression can be a plain old list of
binary (string).

So, we maybe xmerl_xpath already has 99% of what's needed...

Cheers,

Darach.
Post by unknown
Let me tell you something about yourself.
I have been told this bit can be considered offensive in English, it isn't
meant to be.
--
Lo?c Hoguin
Erlang Cowboy
Nine Nines
http://ninenines.eu
______________________________**_________________
erlang-questions mailing list
erlang-questions
http://erlang.org/mailman/**listinfo/erlang-questions<http://erlang.org/mailman/listinfo/erlang-questions>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20130125/52673899/attachment.html>
unknown
2013-01-25 15:08:50 UTC
Permalink
Manipulating nested records is a pain - how about this?

Assume we have three records

-record(top, {a::#one{}, b::#two{}, c::#three{} }).
-record(one, {x::#foo{}, y::#bar{} })
-record(foo, {p,q,r}).
and I want to unpack the p field from a variable X containing a top
record.

I don't want to write

#top{a=#one{x=#foo{p=P}}} = X

this is messy and error prone

This should do the job

P = extract_from(X, top,p)

A compile transform could figure out the code to make. In this case the
tag p has a unique path from the top root. In the case where the required
tag is not unique, we'll need to "hint" the path.

We just give the parse transform enough hints to figure out
the path at compile time. We should get a error if the path does not
uniquely
specify the element.

Cheers

/Joe
Post by unknown
Hi guys,
There is a problem here. Any reasonably sized or structured erlang
application
requires records, despite the grody record syntax. The alternative? Big
hairy unstructured
clods of tuple and lists and things? Worse. Unmaintainable in and of
itself. Hard to pattern
match. Had to manipulate. Hard for humans to grok whilst reading without
squinting your
brain hard and quizzically at the terminal ...
Unlike the matrix, it's not blonde, brunette or a redhead ... It's
something else! ;(
So they're needed? Yes. Use by choice? No. And that's the problem.
I secretly hope for for something better to come along. A big gnarly
unstructured
and frequently accessed tuple would be fine, for example, if there was
some kind
of tuple path expression language... like XML has XPath? Jackpot.
So maybe frames aren't needed at all. Maybe frames would be nice. Perhaps we
just want to reach out and touch the a subset of tuples of lists of tuples
of lists of
tuples of ... I'm pretty sure with or without frames that solves 80% of
the need for me.
The other 20%? - Native support for Kaysian transforms and other natural
conveniences
for efficient slicing, dicing, filtering and merging.
I'm not sure record or any other syntax is actually the problem.
Also, the nice thing about adding something like an XPath like thing for
tuples?
It doesn't break existing applications. It's backward compatible. It's
forward
migratable. No new syntax because an expression can be a plain old list of
binary (string).
So, we maybe xmerl_xpath already has 99% of what's needed...
Cheers,
Darach.
Post by unknown
Post by unknown
Let me tell you something about yourself.
I have been told this bit can be considered offensive in English, it
isn't meant to be.
--
Lo?c Hoguin
Erlang Cowboy
Nine Nines
http://ninenines.eu
______________________________**_________________
erlang-questions mailing list
erlang-questions
http://erlang.org/mailman/**listinfo/erlang-questions<http://erlang.org/mailman/listinfo/erlang-questions>
_______________________________________________
erlang-questions mailing list
erlang-questions
http://erlang.org/mailman/listinfo/erlang-questions
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20130125/b8a6c57f/attachment.html>
unknown
2013-01-25 15:55:06 UTC
Permalink
Hi all,

There are two schools of thought here. One would like to put all the data
in a giant nested data structure and the other would like to split it up
into the smallest possible parts. I think that was what David G. hinted at
before, but he didn't put the final dot over the i.

Having a single huge immutable nested data structure would require the kind
of access patterns exemplified by "character.current_weapon.score", but is
not without other kind of problems. I can think of three important ones.
(1) You would need another syntax for "character.bag_item(12).supply" or
"character.friend('Bilbo').weapon", for example. This is alleviated by
Joe's suggestion, where one can use all kind of selectors. (2) All updating
must be done from the root or in several steps, so i f I have
X=Character.weapon, X.score=10, I need to remember to Character.weapon=X.
(3) Changing the implementation of an item to another data structure might
be problematic without changing all the call sites.

On the other side, that David described, one could have a character
process, a weapon process, a bag process and so on. Then, using a construct
that Joe suggested oh so many years ago, you could write
Character!!weapon!!score to retrieve it and Character!!weapon!!{score, 30}
to set it. The !! operator is a 'rpc' and is conceptually a send followed
by a receive. The processes will be effectively implement active objects.

My feeling is that the latter option is more Erlang-y, but it may be a
matter of taste.

best regards,
Vlad
Post by unknown
Manipulating nested records is a pain - how about this?
Assume we have three records
-record(top, {a::#one{}, b::#two{}, c::#three{} }).
-record(one, {x::#foo{}, y::#bar{} })
-record(foo, {p,q,r}).
and I want to unpack the p field from a variable X containing a top
record.
I don't want to write
#top{a=#one{x=#foo{p=P}}} = X
this is messy and error prone
This should do the job
P = extract_from(X, top,p)
A compile transform could figure out the code to make. In this case the
tag p has a unique path from the top root. In the case where the required
tag is not unique, we'll need to "hint" the path.
We just give the parse transform enough hints to figure out
the path at compile time. We should get a error if the path does not
uniquely
specify the element.
Cheers
/Joe
Post by unknown
Hi guys,
There is a problem here. Any reasonably sized or structured erlang
application
requires records, despite the grody record syntax. The alternative? Big
hairy unstructured
clods of tuple and lists and things? Worse. Unmaintainable in and of
itself. Hard to pattern
match. Had to manipulate. Hard for humans to grok whilst reading without
squinting your
brain hard and quizzically at the terminal ...
Unlike the matrix, it's not blonde, brunette or a redhead ... It's
something else! ;(
So they're needed? Yes. Use by choice? No. And that's the problem.
I secretly hope for for something better to come along. A big gnarly
unstructured
and frequently accessed tuple would be fine, for example, if there was
some kind
of tuple path expression language... like XML has XPath? Jackpot.
So maybe frames aren't needed at all. Maybe frames would be nice. Perhaps we
just want to reach out and touch the a subset of tuples of lists of
tuples of lists of
tuples of ... I'm pretty sure with or without frames that solves 80% of
the need for me.
The other 20%? - Native support for Kaysian transforms and other natural
conveniences
for efficient slicing, dicing, filtering and merging.
I'm not sure record or any other syntax is actually the problem.
Also, the nice thing about adding something like an XPath like thing for
tuples?
It doesn't break existing applications. It's backward compatible. It's
forward
migratable. No new syntax because an expression can be a plain old list of
binary (string).
So, we maybe xmerl_xpath already has 99% of what's needed...
Cheers,
Darach.
Post by unknown
Post by unknown
Let me tell you something about yourself.
I have been told this bit can be considered offensive in English, it
isn't meant to be.
--
Lo?c Hoguin
Erlang Cowboy
Nine Nines
http://ninenines.eu
______________________________**_________________
erlang-questions mailing list
erlang-questions
http://erlang.org/mailman/**listinfo/erlang-questions<http://erlang.org/mailman/listinfo/erlang-questions>
_______________________________________________
erlang-questions mailing list
erlang-questions
http://erlang.org/mailman/listinfo/erlang-questions
_______________________________________________
erlang-questions mailing list
erlang-questions
http://erlang.org/mailman/listinfo/erlang-questions
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20130125/f4c337a0/attachment.html>
unknown
2013-01-25 16:34:21 UTC
Permalink
Since there has been some discussion about "real" code, I can provide some.
The extract below comes the latest project I am working on and it was
extracted from a gen server. Gen servers are spawned by a simple one by one
supervisor and each represents a building. The gen server needs to keep
track of:

1. How many people (i.e. users) are in the building overall;

2. And how many of those users are on each level. Users in the same
building can comunicate with each other via codes and each code is tied to
a socket pid;

3. The users dict in state contains a user_id -> #user relation. And the
levels dict in state contains a level_id -> [user_id] relation (I am
keeping this as a reverse index instead of a levels list inside each user
because this is how I access this data);

-record(state, { levels=dict:new(), users=dict:new(), review=30000,
company_id=undefined }).
-record(user, { codes=dict:new() }).
-record(code, { pid=nil, counter=0 }).

There is more information in the system but that is in a database because
the gen server does not care about it. The state record is what is passed
around gen server callbacks.

As Lo?c previously said, I like to treat all the information above as data.
If the user gets a new code, I would like to simply add it to the codes
dictionary in the user. This is how it looks like:

User1 = User#user{ codes=dict:store(Code, #code{pid=Pid},
User#user.codes) },
Users1 = dict:store(UserId, User1, Users),
{ reply, ok, State#state{users=Users1} }.

And that is because the snippet above is *not* showing how the User, Users
and Code variables were retrieved. Indeed, it could be much better and we
don't even need to compare with PHP, which contains mutable data
structures. For instance, Clojure provides an assoc_in[1] (and related
functions) that would allow me to write all of this as:

{ reply, ok, assoc_in(State, [users, UserId, codes], Code,
#code{pid=Pid}) }

Which is similar to what the kvc project does. Others have mentioned lenses
as well. My point is that it seems to be a common issue and others seem to
be looking for (or have found) a streamlined solution, which they can
present and introduce to developers using and learning the language.

[1]: http://clojuredocs.org/clojure_core/1.2.0/clojure.core/assoc-in


*Jos? Valim*
www.plataformatec.com.br
Skype: jv.ptec
Founder and Lead Developer
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20130125/eeed9642/attachment.html>
unknown
2013-01-26 04:04:28 UTC
Permalink
Post by unknown
Manipulating nested records is a pain - how about this?
Assume we have three records
-record(top, {a::#one{}, b::#two{}, c::#three{} }).
-record(one, {x::#foo{}, y::#bar{} })
-record(foo, {p,q,r}).
and I want to unpack the p field from a variable X containing a top
record.
Disagreeing with Joe Armstrong in the Erlang mailing list is
rather like arguing with God, but if Honi the circle-drawer
got away with it,
maybe I'll survive.

Why should I assume that? What does a real example look like?
Post by unknown
I don't want to write
#top{a=#one{x=#foo{p=P}}} = X
I don't mind writing that. Once.
In one place.
And naming it.

Ideally, I'd write

#american_express(<{a ~ <{ x ~ <{ p ~ X }>}>}> -> X.

but even

american_express(AXP) ->
AXP#top.a#one.x#foo.p.

will do.

There's a style guideline I've been feeling my way
towards over the last couple of years, and this
thread is helping me to clarify it, but I'm not
quite there yet. It's something like

"no multi-clause construct should cross more than
one abstraction layer."

I don't count a #state record that merely aggregates
a bunch of state variables as an abstraction layer;
I do count a record that might escape from the boundaries
of its module as an abstraction layer.

So I don't _want_ to write AXP.a.x.p because that code
frightens me with its fragility. The only x.a.b or
x->a->b I could find in a quick find+grep over my own
C code on this laptop were two lines in some code to
handle doubly linked lists.

If I don't do this sort of thing in C,
why would I be doing it in Erlang?

Just for the sake of pointing out that there _are_
alternatives, let me suggest another approach that
could be taken with records.

Suppose we spotted that .a.x.p was used often enough
to be worth worrying about. We might decide that it
was worth storing redundantly. After all, memory
references are _expensive_ on modern machines.

So let's introduce the notion of a *virtual* field.
A virtual field looks just like an ordinary field,
except that you cannot update it, and it is computed,
not fetched. We'll use

Field_Name -> Expression

as the syntax, where Expression is a guard expression
so that we can still use records in patterns, and
may include THIS.

Now we define

-record(top, {
a :: #one{},
b :: #two{},
c :: #three{},
axp -> THIS#top.a#one.x#foo.p
}).
-record(one, {
x :: #foo{},
y :: #bar{}
}).
-record(foo, {
p,
q,
r
}).

and use

#top(axp = P) = X

or
P = X#top.axp

This code follows the Law of Demeter. After the definitions,
the source code no longer assumes very much about #top and
*nothing* about #one or #foo, not even that they exist.
All it assumes about #top is that a #top record knows how to
find .axp *somehow* (and safely).

Once the code has been rewritten to use the virtual field,
we can change the definition so that the field is stored
concretely.

(Aside.) Given that I don't like records very much, and
invented abstract patterns and frames so that we could get
rid of them, I'm not that thrilled that I've just made
records do something frames can't do at all. Oh well, this
is just an example, not an EEP. (End aside.)

(Second aside.) Having warned you that this is just an
alternative to prove that alternatives are possible, this
_is_ something we could practically do, and it _could_
shorten code, and it _could_ simplify a transition from one
representation to another. Maybe it does deserve serious thought.
(End second aside.)
unknown
2013-01-26 10:15:07 UTC
Permalink
Post by unknown
So I don't _want_ to write AXP.a.x.p because that code
frightens me with its fragility. The only x.a.b or
x->a->b I could find in a quick find+grep over my own
C code on this laptop were two lines in some code to
handle doubly linked lists.
Imagine me with egg all over my face.
Somehow that find+grep missed an entire directory,
containing a project with lots of code by me and
nobody else, containing hundreds of examples of
what I said I didn't do.

Some of the code is actually benign. It's not *really*
spanning multiple records. I have a lot of tagged unions,
struct Thingy {
enum Thingy_Tag tag;
union {
int i;
Unique_String s;
...
} u;
}
and occurrences of thingy->u.s really count as a single
field reference.

However, there were also about 300 lines containing
foo->bar->ugh and I have spent a couple of hours
fixing as many of them as I could.

In many cases, the code was (to my mind) simplified
and clarified by introducing
gvar const o = m->owner;
... o->whatever ...
instead of m->owner->whatever, because it turned out
that o was actually used several times in a function
containing such a double step. Simply, if I was using
foo->bar->ugh I was almost always _also_ using
foo->bar->zoo and/or plain foo->bar itself. Before C
compilers got good at optimising, this change would
also have made the object code smaller and faster;
even these days, C's aliasing rules probably mean there's
some benefit there.

I've spotted this in other people's Erlang code too.
Function bodies that contain lots of field references
can often be shortened (and to my mind simplified) by
replacing field references by pattern matching in the
head.

Of the rest, quite a few would have benefited from
virtual fields, had C supported them. Some of the
ones that are left would have been simpler and easier
for the compiler to type-check had I *not* been using
C format strings. (The whole program basically doubled
in speed when I stopped using <stdio.h> for most I/O;
the only stdio code left is for error messages.)

But to me the most interesting thing was recalling,
as I worked over the code, that these had been the
most error prone parts of the program. foo->bar->ugh
really _had_ been a warning sign that I had not
understood years ago when writing this stuff.

Not only that: the foo->bar->ugh antipattern turned up
a lot in code that needs a rewrite in order to hold
Unicode in certain internal data structures, and I'd
been putting that off and putting it off because fixing
this stuff was so scary. I hadn't understood _why_ it
was scary, but now I think I do.

Why has it taken me so long to learn not to be so stupid?
unknown
2013-01-26 13:05:52 UTC
Permalink
Hi guys,

My apologies for not introducing what a Kaysian transform is. It's basically
a technique discovered by Michael Kay (long time XPath / XSLT guy,
wrote/leads
Saxon) for efficient set intersection and difference with XPath. It's a
neat little efficiency
trick. It's documented in the following (page 3), with other neat tricks:

http://www.xml.org//sites/www.xml.org/files/xslt_efficient_programming_techniques.pdf

On the schemey/lispy approach? I like it. If the structures are reasonably
stable with respect to
change over time then some artful hiding behind accessor functions is good
enough. I do it myself
for things like gen_server state (accessors) or process options (mutators).
I agree with Joe too.
If a parse transform compiles away some inefficiency (human or systemic)
then that's a better
accessor.

But would I maintain the structures for a family of complex financial
derivative instruments
in erlang today and/or represent them as erlang records? No, not with the
same accessors and/or
code generators I'd be happy to write and use for other isolated tasks. The
reason is simple. The
number of, complexity of, frequency of change, and continuous arrival and
departure of newly
invented structures would mean a lot of maintenance and upheaval. It's a
significant source of pain
in capital markets and the problem is not exclusive to any one language. At
some point you're
going to end up compromising and accept a certain level of maintenance.

So maybe there isn't one perfect solution. Maybe there's a few good partial
solutions and each
is optimal given a certain presumed level of maintenance. But to presume
all environments are
dealing with fairly trivial structures like the examples thus far, or that
they are few in volume,
or that the frequency of change of those structures is low? That is an auto
selection problem.

I see more than one good approach but no right one here.

Cheers,

Darach.
Post by unknown
Post by unknown
So I don't _want_ to write AXP.a.x.p because that code
frightens me with its fragility. The only x.a.b or
x->a->b I could find in a quick find+grep over my own
C code on this laptop were two lines in some code to
handle doubly linked lists.
Imagine me with egg all over my face.
Somehow that find+grep missed an entire directory,
containing a project with lots of code by me and
nobody else, containing hundreds of examples of
what I said I didn't do.
Some of the code is actually benign. It's not *really*
spanning multiple records. I have a lot of tagged unions,
struct Thingy {
enum Thingy_Tag tag;
union {
int i;
Unique_String s;
...
} u;
}
and occurrences of thingy->u.s really count as a single
field reference.
However, there were also about 300 lines containing
foo->bar->ugh and I have spent a couple of hours
fixing as many of them as I could.
In many cases, the code was (to my mind) simplified
and clarified by introducing
gvar const o = m->owner;
... o->whatever ...
instead of m->owner->whatever, because it turned out
that o was actually used several times in a function
containing such a double step. Simply, if I was using
foo->bar->ugh I was almost always _also_ using
foo->bar->zoo and/or plain foo->bar itself. Before C
compilers got good at optimising, this change would
also have made the object code smaller and faster;
even these days, C's aliasing rules probably mean there's
some benefit there.
I've spotted this in other people's Erlang code too.
Function bodies that contain lots of field references
can often be shortened (and to my mind simplified) by
replacing field references by pattern matching in the
head.
Of the rest, quite a few would have benefited from
virtual fields, had C supported them. Some of the
ones that are left would have been simpler and easier
for the compiler to type-check had I *not* been using
C format strings. (The whole program basically doubled
in speed when I stopped using <stdio.h> for most I/O;
the only stdio code left is for error messages.)
But to me the most interesting thing was recalling,
as I worked over the code, that these had been the
most error prone parts of the program. foo->bar->ugh
really _had_ been a warning sign that I had not
understood years ago when writing this stuff.
Not only that: the foo->bar->ugh antipattern turned up
a lot in code that needs a rewrite in order to hold
Unicode in certain internal data structures, and I'd
been putting that off and putting it off because fixing
this stuff was so scary. I hadn't understood _why_ it
was scary, but now I think I do.
Why has it taken me so long to learn not to be so stupid?
_______________________________________________
erlang-questions mailing list
erlang-questions
http://erlang.org/mailman/listinfo/erlang-questions
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20130126/95306c19/attachment.html>
unknown
2013-01-28 01:01:03 UTC
Permalink
This is _so_ on-topic...

http://thedailywtf.com/Articles/Ancestors.aspx

From reading
http://www.xml.org//sites/www.xml.org/files/xslt_efficient_programming_techniques.pdf
it appears that the Kaysian technique is a horrible kluge to work around
the fact that XPath 1.0 does not have set operations.

XPath 2.0 _does_ have set operations:
3.3.3 Combining Node Sequences

[14] UnionExpr ::= IntersectExceptExpr ( ("union" | "|") IntersectExceptExpr )*
[15] IntersectExceptExpr ::= InstanceofExpr ( ("intersect" | "except") InstanceofExpr )*

It would be interesting to see measurements of intersections computed
using "say-exactly-what-you-mean" vs "Kaysian-kluge".
Given that the results of union, intersect, except are returned in document order,
these operations would _probably_ be implemented as linear time merges; hard to beat.
unknown
2013-01-25 16:51:53 UTC
Permalink
Post by unknown
*Data*. Not code. Access. Update. That's all that's needed.
Alright, here's a 15 minutes attempt at getting some monster design
working based on tuple lists, but any data structure that's dynamic
enough (not records) would probably do. No benchmarking, no testing,
but you can pretty much use lists of accessors in verbose manner, but
less verbose than your usual dictionary or k/v use.

Here's how the code is used (I used terrible function names on
purpose!):

test() ->
%% build
Char1 = '='('='('='('='('0'(),
[name], karl),
[current,weapon,points], 10),
[current,weapon,name], "crappy sword"),
[stats, level], 3),
Skills = '='('='('='('0'(),
[strength], 12),
[charisma], 7),
[luck], 3),
Char = '='(Char1, [stats,skills], Skills),

%% read
[{strength, '?'(Char, [stats,skills,strength])},
{item, {'?'(Char, [current,weapon,name]),
'?'(Char, [current,weapon,points])}},
{damage, '?'(Char, [current,weapon,points]) *
'?'(Char, [stats,skills,strength]) +
'?'(Skills, [luck])}
].

'='/3 sets fields, '?'/2 reads from them. Note that you
can either build everything from the top level (Like 'Char1' does)
or do it in incremental steps (the way 'Skills' is done). Fetching
respects the same concept.

And here's the output:

1> hubble:test().
[{strength,12},
{item,{"crappy sword",10}},
{damage,123}]

That seems to work. And here's the code

-module(hubble).
-export(['0'/0, '='/3, '?'/2]).
-export([test/0]).

'0'() -> [].

'='(L, Fields, Val) ->
set(L, Fields, Val).

'?'(L, Fields) ->
fetch(L, Fields).

set([], [K], V) ->
[{K,V}];
set(L, [K], V) ->
lists:keystore(K, 1, L, {K,V});
set(L, [K|T], V) ->
case lists:keyfind(K, 1, L) of
false ->
lists:keystore(K, 1, L, {K, set([], T, V)});
{K,Old} ->
lists:keyreplace(K, 1, L, {K, set(Old, T, V)})
end.

fetch(L, [K]) ->
case lists:keyfind(K, 1, L) of
false -> undefined;
{K,V} -> V
end;
fetch(L, [H|T]) ->
{H, L2} = lists:keyfind(H, 1, L),
fetch(L2,T).

Basic list functionality with a tiny wrapper, no parse
transform, usable as a library over any k/v data type today.

There's probably a connection to be made to jlouis' lenses in
how this is organized.

I'm guessing someone with more than 15 minutes could probably
make a decent parse transform out of it, overload some syntax
or whatever and get it to a more usable/pretty level. The mechanism
seems to generaly work, though.

Regards,
Fred.
unknown
2013-01-25 18:16:24 UTC
Permalink
Post by unknown
Post by unknown
*Data*. Not code. Access. Update. That's all that's needed.
Alright, here's a 15 minutes attempt at getting some monster design
working based on tuple lists, but any data structure that's dynamic
enough (not records) would probably do. No benchmarking, no testing,
but you can pretty much use lists of accessors in verbose manner, but
less verbose than your usual dictionary or k/v use.
Let's compare this:

Strength = '?'(Char, [stats,skills,strength])}

to this:

Strength = Char.stats.skills.strength

Now, which would a beginner prefer? The first version is *terrifying*.
And if the programmer *could* brave the syntax, what about all that
extra typing?? Just looking at that code makes my fingers tired :(

That's why Ruby is #2 on github language ranks and Erlang isn't even
in the top 10! [1]

Imagine the boundless creativity Erlang will never harness because
it's so hard to navigate deeply nested data structures using dots!

Or course this is absurd. But it's the basis of this thread.

The debate has become how we should represent a particular operation,
when in Erlang, it should be clear -- you use a function:

get_strength(Char)

and if that contract is overly specific:

get_attr(strength, Char)

Inside that function you can do whatever want. The function is a
contract. It's easy to type, easy to read, easy to use.

You want to update?

set_attr(strength, "muscley", Char)

So, a game developer has a requirement to easily and efficiently
navigate a deeply nested data structure, and optionally apply
transformations along the way. [2] Okay, that's the requirement.
Erlang term manipulation can *conceivably* be used for that, but upon
casual inspection, it's *obviously* not well suited.

I offhand don't know what is best suited as an implementation. It's an
engineering problem.

But I do know that however it's implemented, gaming programmers should
not be exposed to those details. They should get a simple, easy to use
interface. If Erlang functions are too painful or otherwise unnatural
to use, create a DSL.

With a DSL, game programmers can use whatever syntax they care to
invent. And you can plug in engines behind that interface as you see
fit.

Depending on the performance, scalability, and reliability
requirements, the implementation of this gaming infrastructure could
be wildly different, of course.

Here are some other ways you *could* implement the
game-engine-state-problem described:

- ets/dets

- Relational database (SQLite, MySQL, PostreSQL)

- Graph database (I only know of Neo4J, but Erlang talks to Java)

- Redis

- Riak

- Some crazy heap navigator in C over a port -- or a NIF!

- Python + ErlPort

- Embedded Lua with an R backend -- go crazy!!

Whatever. It all sits behind an interface that is clear, simple, even fun!

Now, as far as using Erlang to create DSLs, I think you have an
interesting topic. [3]

Garrett

[1] https://github.com/languages

[2] I'm reminded of the coding horror that is jQuery

[3] I'd point to Eric Merrit's outstanding with with Joxa
(http://joxa.org) as an example of what can be done with core Erlang
and the Erlang tool chain
unknown
2013-01-25 18:26:52 UTC
Permalink
Post by unknown
Strength = '?'(Char, [stats,skills,strength])}
Strength = Char.stats.skills.strength
Now, which would a beginner prefer? The first version is *terrifying*.
And if the programmer *could* brave the syntax, what about all that
extra typing?? Just looking at that code makes my fingers tired :(
That's why Ruby is #2 on github language ranks and Erlang isn't even
in the top 10! [1]
Of course it's terrible. It's a 15 minutes attempt to show it's doable
to navigate deeply nested data structures. I might as realistically make
a function that accepts:

Char = set(new, stats,skills,strength, 50)
Strength = get(Char, stats,skills,strength)

by using parse transforms (you can get list of args and redistribute
them the way you want, iirc), using my module from the previous e-mail as
the underlying representation. This can be done as a blind replacement,
without any new support from the language, with currently existing
tools, and work on pretty much any reasonable depth. Someone just has to
go through the trouble of doing it. Plus you could automatically change
representations by having different parse transforms. One for tuple
lists, one for dicts, one for ETS, whatever you feel like.

These two versions are not significantly annoying -- they don't even
need annotations for types or pointers or whatever the way many
languages would need them. Clearly they would be concise enough.

There are reasons for Erlang to not be that used, but accessors for deep
data structures are likely not the most important part of it. I'd
probably bet on the difficulty to translate algorithms that assume O(1)
access to hashes or arrays, with destructive updates, as a significant
barrier of entries with far fewer easy workarounds.

That's all speculation anyway.

Regards,
Fred.
unknown
2013-01-25 18:34:44 UTC
Permalink
Post by unknown
Post by unknown
Strength = '?'(Char, [stats,skills,strength])}
Strength = Char.stats.skills.strength
Now, which would a beginner prefer? The first version is *terrifying*.
And if the programmer *could* brave the syntax, what about all that
extra typing?? Just looking at that code makes my fingers tired :(
That's why Ruby is #2 on github language ranks and Erlang isn't even
in the top 10! [1]
Of course it's terrible. It's a 15 minutes attempt to show it's doable
to navigate deeply nested data structures. I might as realistically make
Char = set(new, stats,skills,strength, 50)
Strength = get(Char, stats,skills,strength)
Indeed, I was just using your code as a straw man :)

When chaining operations like that, I too use lists. It's the natural
thing to do in Erlang for that case I think.

-snip-
Post by unknown
There are reasons for Erlang to not be that used, but accessors for deep
data structures are likely not the most important part of it. I'd
probably bet on the difficulty to translate algorithms that assume O(1)
access to hashes or arrays, with destructive updates, as a significant
barrier of entries with far fewer easy workarounds.
That's all speculation anyway.
Precisely!

Garrett
unknown
2013-01-25 20:08:28 UTC
Permalink
I work at a game-development studio so I can chime in on some of this.

First, real world data =/= designed data. What I mean by this is that real
world data (mined from measurements or analytics or something) tends to fit
certain patterns and have even levels of nesting, so that something like
nested proplists or dicts can be easy to reason about. Once we are
referring to data that pertains to game data, the data isn't "nice"
anymore. To take Loic's example: suppose I design a character to have an
arsenal of weapons. When I initially implement this, a flat data structure
is fine. Later however, design changes, and now some weapons (not all) can
be outfitted with a weapon add-on, like a scope or laser sight. Other
weapons can be upgraded. A future design might even allow for the scope
itself to be upgraded. Coming up with a way to represent this in Erlang
such that it can be *flexibly* expanded on without changing api and
implementation everywhere is very difficult. I can say that nested
proplists and dicts and lists are very cumbersome to work with because
there are no enforced contracts with the developer.

Incidentally, I can understand why bringing up OO ruffles feathers, but
what is wrong about discussing how to represent objects themselves?

Personally, I wish something like C-structs were available I suppose. The
fact is, sometimes, data is deeply nested, and we should be able to talk
about nested representations for them (with convenient accessors).
Post by unknown
Post by unknown
Post by unknown
Strength = '?'(Char, [stats,skills,strength])}
Strength = Char.stats.skills.strength
Now, which would a beginner prefer? The first version is *terrifying*.
And if the programmer *could* brave the syntax, what about all that
extra typing?? Just looking at that code makes my fingers tired :(
That's why Ruby is #2 on github language ranks and Erlang isn't even
in the top 10! [1]
Of course it's terrible. It's a 15 minutes attempt to show it's doable
to navigate deeply nested data structures. I might as realistically make
Char = set(new, stats,skills,strength, 50)
Strength = get(Char, stats,skills,strength)
Indeed, I was just using your code as a straw man :)
When chaining operations like that, I too use lists. It's the natural
thing to do in Erlang for that case I think.
-snip-
Post by unknown
There are reasons for Erlang to not be that used, but accessors for deep
data structures are likely not the most important part of it. I'd
probably bet on the difficulty to translate algorithms that assume O(1)
access to hashes or arrays, with destructive updates, as a significant
barrier of entries with far fewer easy workarounds.
That's all speculation anyway.
Precisely!
Garrett
_______________________________________________
erlang-questions mailing list
erlang-questions
http://erlang.org/mailman/listinfo/erlang-questions
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20130125/38082481/attachment.html>
unknown
2013-01-25 22:35:02 UTC
Permalink
Post by unknown
Post by unknown
Strength = '?'(Char, [stats,skills,strength])}
Strength = Char.stats.skills.strength
Now, which would a beginner prefer? The first version is *terrifying*.
And if the programmer *could* brave the syntax, what about all that
extra typing?? Just looking at that code makes my fingers tired :(
That's why Ruby is #2 on github language ranks and Erlang isn't even
in the top 10! [1]
Of course it's terrible. It's a 15 minutes attempt to show it's doable
to navigate deeply nested data structures. I might as realistically make
Char = set(new, stats,skills,strength, 50)
Strength = get(Char, stats,skills,strength)
by using parse transforms (you can get list of args and redistribute
them the way you want, iirc), using my module from the previous e-mail as
the underlying representation. This can be done as a blind replacement,
without any new support from the language, with currently existing
tools, and work on pretty much any reasonable depth. Someone just has to
go through the trouble of doing it.
That's the point: it should be *built into the language*, you shouldn't
have to go through the trouble of doing something like this. And it
should be *obvious* and in line with the rest of the language. I quite
like the xpath idea Darach mentioned. It could integrate very well with
the rest of the language. I might experiment with it.
--
Lo?c Hoguin
Erlang Cowboy
Nine Nines
http://ninenines.eu
unknown
2013-01-25 22:37:24 UTC
Permalink
please contribute to getting LFE back in motion.
$0.02,
sincerely.
unknown
2013-01-26 00:13:27 UTC
Permalink
Hi guys,

I have no beef with these parse transforms you speak of. But, I haven't
used them so will stop at wishing them good health - maybe pencil in a few
hours
with them as penance for my non-erlangy sins too. :)

I think folk new to erlang will likely be familiar with XML Path though. So
picking up a variant based on XPath 1.0 would be fairly natural. I'm
clutching
at straws here, but maybe parse transforms have a role to play here too.

I see no reason why Joe's selector couldn't be bound as function in some
kind of erlangy xpath for tuples. So we would get something like:

P = tpath:scan(X, "/top/a/x/p").

No hints required. The path is explicit. The hints in the parse transform
would equate to the following XPath

P = tpath:scan(X, "/top//p").

If the structure changed so there was a list of x's and we just want the p
from the first occurrence?

P = tpath:scan(X, "/top/x[first()]/p").

Maybe I want all p's matched on some guard or filter?

P = tpath:scan(X, "/top/x[key =/= 'corba']/p[@a]").

And, maybe parse transforms, funs could be plugged in too ...

P = tpath:scan(X, "some_module:some_fun(//p[@a)").

Perhaps I'm stuck with the xpath style bag because it's familiar
and I've been using it for ~14 years. The cool young kids might
prefer a more jsony selection experience. I could live with that:

P = jsony:scan(X, "top.a.x.p");

But this: #top{a=#one{x=#foo{p=P}}} = X

I can barely parse it visually. It's too noisy, too busy.

Cheers,

Darach.
Post by unknown
please contribute to getting LFE back in motion.
$0.02,
sincerely.
_______________________________________________
erlang-questions mailing list
erlang-questions
http://erlang.org/mailman/listinfo/erlang-questions
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20130126/378e551e/attachment.html>
unknown
2013-01-26 17:37:27 UTC
Permalink
I suggest spending some time with Joxa... it goes well beyond LFE.
Post by unknown
please contribute to getting LFE back in motion.
$0.02,
sincerely.
_______________________________________________
erlang-questions mailing list
erlang-questions
http://erlang.org/mailman/listinfo/erlang-questions
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20130126/2f4a8a60/attachment.html>
unknown
2013-01-27 05:31:35 UTC
Permalink
In the mean time, enjoy an implementation of it:

https://github.com/ferd/hubble

Allows the following mode:

demo() ->
Stats = hubble:puts(hubble:new(),
[{[strength], 12},
{[wisdom], 9},
{[luck], 10},
{[dexterity], 5}]),
Char = hubble:puts(hubble:new(),
[{[name], <<"karl">>},
{[bio, age], 219},
{[bio, hometown], <<"The Internet">>},
{[bio, parent, father], undefined},
{[bio, parent, mother], <<"A Unicorn">>},
{[stats], Stats}]),
Char2 = hubble:put(Char, [level], 1),
Char3 = hubble:up(Char2, [bio,parent,father], <<"Randalf">>),
9 = hubble:get(Char3, [stats,wisdom]),
<<"A Unicorn">> = hubble:get(Char3, [bio,parent,mother]),
<<"Randalf">> = hubble:get(hubble:get(Char3, [bio,parent]), [father]).

Or, using a parse transform:

-compile({parse_transform, hubble_trans}).

demo() ->
Stats = puts(new(),
[strength, 12],
[wisdom, 9],
[luck, 10],
[dexterity, 5]),
Char = puts(new(),
[name, <<"karl">>],
[bio, age, 219],
[bio, hometown, <<"The Internet">>],
[bio, parent, father, undefined],
[bio, parent, mother, <<"A Unicorn">>],
[stats, Stats]),
Char2 = put(Char, level, 1),
Char3 = up(Char2, bio,parent,father, <<"Randalf">>),
9 = get(Char3, stats, wisdom),
<<"A Unicorn">> = get(Char3, bio, parent, mother),
<<"Randalf">> = get(get(Char3, bio, parent), father).

And it lets you use any damn term you please for the path, not just yet
another overloaded bunch of strings with encodings to worry about.

The README.md file has a bit more details.

Regards,
Fred.
Post by unknown
That's the point: it should be *built into the language*, you
shouldn't have to go through the trouble of doing something like
this. And it should be *obvious* and in line with the rest of the
language. I quite like the xpath idea Darach mentioned. It could
integrate very well with the rest of the language. I might
experiment with it.
--
Lo?c Hoguin
Erlang Cowboy
Nine Nines
http://ninenines.eu
unknown
2013-01-27 09:46:21 UTC
Permalink
Post by unknown
https://github.com/ferd/hubble
You're not fixing the issue, it still has no language support. In short
it means:

* Can't pattern match
* Can't use values with function clause guards
* Can't modify values at different depths in one go

Seems it's also quite verbose and you have to repeat paths all the time,
similar to how you have to repeat the record name all the time.
Post by unknown
And it lets you use any damn term you please for the path, not just yet
another overloaded bunch of strings with encodings to worry about.
No idea what this means.
Post by unknown
Post by unknown
That's the point: it should be *built into the language*, you
shouldn't have to go through the trouble of doing something like
this. And it should be *obvious* and in line with the rest of the
language. I quite like the xpath idea Darach mentioned. It could
integrate very well with the rest of the language. I might
experiment with it.
--
Lo?c Hoguin
Erlang Cowboy
Nine Nines
http://ninenines.eu
--
Lo?c Hoguin
Erlang Cowboy
Nine Nines
http://ninenines.eu
unknown
2013-01-27 17:06:22 UTC
Permalink
Post by unknown
Post by unknown
https://github.com/ferd/hubble
You're not fixing the issue, it still has no language support. In
* Can't pattern match
* Can't use values with function clause guards
* Can't modify values at different depths in one go
Seems it's also quite verbose and you have to repeat paths all the
time, similar to how you have to repeat the record name all the
time.
You indeed:

* Can't pattern match
* Can't use value with function clause guards

If these are 100% necessary and vital, there isn't much to do, although
there could be some forms of pattern matching (see below).

You can modify values at different depths in one go. It would also be
easy to support nested operations where you pretty much draw the tree,
nearly trivial too, so that:

ups(H, [stats, strength, 1],
[stats, wisdom, 2],
[bio, age, 329])

Becomes:

ups(H, [stats, [strength, 1]
[wisdom, 2]],
[bio, age, 329])

This means you can no longer use lists (or strings) as keys, though,
because you couldn't know whether they're nested levels or keys;
another syntax could be found possibly. I don't know when that would
become too cumbersome or not cumbersome enough for your own tastes.

It would maybe be possible to do the deconstruction on the left-hand
side of the match operator. Find the desired fields, shove them in a
tuple, and match on the final values or whatever.

A transformation that targets making a call similar to:

{X,5,Z} = {hubble:get(Hubble,[stats,strength]),
hubble:get(Hubble,[stats,wisdom]),
hubble:get(Hubble,[bio,parent,father])}

would possibly allow a declaration like (I think they'll be allowed this
far down the compilation, but I haven't checked):

match([stats, [strength, X]
[wisdom, 5]],
[bio, parent, father, Z]) = Hubble

That's a far cry from native language support with function heads and
guards. I don't know if you'd still consider this far too cumbersome, if
it's somehow still worse than your aversion to the current record
format:

#character{stats=#stats{strength=X,
wisdom=5},
bio=#bio{parent=#parent{father=Z}}} = Hubble

If there's a common translation accepted of match(Hubble) -> Tuple,
or match(Hubble) -> List, then you could allow the transformation of the
match/1 function as a general rule and be able to pass it to cases and
guards. I'm not sure how reliable that thing would be, and it could not
work with function heads.

It's stuff that can be explored right away, though, without needing
language support, if the need for such a structure or the hate of
records make this really pressing. If it's not that urgent, then oh
well.
Post by unknown
Post by unknown
And it lets you use any damn term you please for the path, not just yet
another overloaded bunch of strings with encodings to worry about.
No idea what this means.
When XPath was mentioned, I assumed it would be something string-based
like the real XPath libraries use:

"people//author[first-name][3]"

This means whatever your key is, it needs to be a string or an atom,
hope that they use the same encoding, escape values that could have been
used, etc.

I feel it's generally more interesting to be able to have mixed-type
keys for some operations on dict-like data structures. Say I have a
gen_event with registered handlers {make_ref(), Name}. Using these for
keys becomes impossible with a string matching syntax.

Maybe most people wouldn't care about that, though, and xPathing could
be interesting. I'm not sure how you could use that to pattern match
while binding values though.


Regards,
Fred.
unknown
2013-01-27 18:28:50 UTC
Permalink
Post by unknown
Garrett
[1] https://github.com/languages
[2] I'm reminded of the coding horror that is jQuery
[3] I'd point to Eric Merrit's outstanding with with Joxa
(http://joxa.org) as an example of what can be done with core Erlang
and the Erlang tool chain
We will probably be hoisting Joxa up from Core Erlang to the higher
level Erlang AST sometime soon. Unfortunately, Core Erlang isn't
really the first class language target that it is claimed. The main
problem is it does not produce Abstract Code in the resulting beam.
This makes it impossible to use both Erlang's built in debugger and
Dialyzer on things compiled to Core Erlang. It could be argued that
this isn't a major problem. In Joxa, at least, the lack of those
features have been somewhat painful for new folks.

On the plus side Core Erlang is a nice, simple AST to target that
gives a lot of flexibility.
Post by unknown
_______________________________________________
erlang-questions mailing list
erlang-questions
http://erlang.org/mailman/listinfo/erlang-questions
unknown
2013-01-29 02:16:35 UTC
Permalink
Post by unknown
Post by unknown
Garrett
[1] https://github.com/languages
[2] I'm reminded of the coding horror that is jQuery
[3] I'd point to Eric Merrit's outstanding with with Joxa
(http://joxa.org) as an example of what can be done with core Erlang
and the Erlang tool chain
We will probably be hoisting Joxa up from Core Erlang to the higher
level Erlang AST sometime soon. Unfortunately, Core Erlang isn't
really the first class language target that it is claimed. The main
problem is it does not produce Abstract Code in the resulting beam.
This makes it impossible to use both Erlang's built in debugger and
Dialyzer on things compiled to Core Erlang. It could be argued that
this isn't a major problem. In Joxa, at least, the lack of those
features have been somewhat painful for new folks.
It sounds like it'd be more work than improving the Core Erlang support
in OTP.

Correct me if I'm wrong:

Dialyzer works on Core Erlang. It needs the abstract code because Core
Erlang has no support for typespecs. When Dialyzer works on beam files,
it extracts typespecs, compiles the abstract code to Core Erlang and
continues with it. It does a similar process from source.

Instead the compilation process could perhaps add a beam chunk
containing the typespec information that Dialyzer would use, and another
with the Core Erlang AST. This'd likely also make Dialyzer a little
faster as it would not need to compile the AST to Core Erlang and to
retrieve values from it.

The debugger application, but not dbg from what I understand, is indeed
making heavy use of the Erlang AST. This sounds like a minor issue
though if dbg still works. I'll need to confirm this later on.

The last two issues are the tools cover and xref. I don't think xref
would be too difficult to port to Core Erlang, cover I'm not sure.
Post by unknown
On the plus side Core Erlang is a nice, simple AST to target that
gives a lot of flexibility.
And we should help make it viable for many languages to come.
--
Lo?c Hoguin
Erlang Cowboy
Nine Nines
http://ninenines.eu
unknown
2013-01-25 16:55:06 UTC
Permalink
Post by unknown
*Data*. Not code. Access. Update. That's all that's needed.
Alright, here's a 15 minutes attempt at getting some monster design
working based on tuple lists, but any data structure that's dynamic
enough (not records) would probably do. No benchmarking, no testing,
but you can pretty much use lists of accessors in verbose manner, but
less verbose than your usual dictionary or k/v use.

Here's how the code is used (I used terrible function names on
purpose!):

test() ->
%% build
Char1 = '='('='('='('='('0'(),
[name], karl),
[current,weapon,points], 10),
[current,weapon,name], "crappy sword"),
[stats, level], 3),
Skills = '='('='('='('0'(),
[strength], 12),
[charisma], 7),
[luck], 3),
Char = '='(Char1, [stats,skills], Skills),
????????
%% read
[{strength, '?'(Char, [stats,skills,strength])},
{item, {'?'(Char, [current,weapon,name]),
'?'(Char, [current,weapon,points])}},
{damage, '?'(Char, [current,weapon,points]) *
'?'(Char, [stats,skills,strength]) +
'?'(Skills, [luck])}
].

'='/3 sets fields, '?'/2 reads from them. Note that you
can either build everything from the top level (Like 'Char1' does)
or do it in incremental steps (the way 'Skills' is done). Fetching
respects the same concept.

And here's the output:

1> hubble:test().
[{strength,12},
{item,{"crappy sword",10}},
{damage,123}]

That seems to work. And here's the code

-module(hubble).
-export(['0'/0, '='/3, '?'/2]).
-export([test/0]).
????
'0'() -> [].
????
'='(L, Fields, Val) ->
set(L, Fields, Val).
????
'?'(L, Fields) ->
fetch(L, Fields).
????
set([], [K], V) ->
[{K,V}];
set(L, [K], V) ->
lists:keystore(K, 1, L, {K,V});
set(L, [K|T], V) ->
case lists:keyfind(K, 1, L) of
false ->
lists:keystore(K, 1, L, {K, set([], T, V)});
{K,Old} ->
lists:keyreplace(K, 1, L, {K, set(Old, T, V)})
end.
????
fetch(L, [K]) ->
case lists:keyfind(K, 1, L) of
false -> undefined;
{K,V} -> V
end;
fetch(L, [H|T]) ->
{H, L2} = lists:keyfind(H, 1, L),
fetch(L2,T).

Basic list functionality with a tiny wrapper, no parse
transform, usable as a library over any k/v data type today.

There's probably a connection to be made to jlouis' lenses in
how this is organized.

I'm guessing someone with more than 15 minutes could probably
make a decent parse transform out of it, overload some syntax
or whatever and get it to a more usable/pretty level. The mechanism
seems to generaly work, though.

Regards,
Fred.
unknown
2013-01-26 02:26:01 UTC
Permalink
Post by unknown
Post by unknown
(1) Please let's have a real concrete example of about 1 page,
not imaginary one-liners, with names that turn out to be
not as intention-revealing as they look.
It's a real concrete example.
The one and only example I have seen so far
was a one-liner involving an imaginary game.
If it isn't an imaginary game, my apologies.
But it was still a one liner, and without any
context to make it interpretable.
Post by unknown
I'm sure you can imagine other examples.
I don't want imaginary examples. Like I said,
please let's have about a page of code, with enough
context to make it intelligible.
Post by unknown
Or perhaps you are going to tell me you never had to manage big amounts
of related data in Erlang? (Wouldn't surprise me.)
I've had to manage sufficient data for a single run
to take days.
Post by unknown
Post by unknown
Are we debating whether Person~name, with the same fundamental
limitation as field access in C or Java or ML, is a really big
improvement over Person#person_name?
Or has the idea crept in that Person.name might run complex code?
*Data*. Not code. Access. Update. That's all that's needed.
Sigh. But does *CARRYING OUT* that access or update involve
running complex code? I mean, fetching a field from a *record*
doesn't count as complex code, but fetching an entry from a
'dict' does count as running complex code, way beyond what
Person#person.name could do.
Post by unknown
Let me tell you something about yourself.
You are confronted with the problem of wasting a lot of time writing
basement level code to access and update deep values.
If confronted with that task, I will refuse to do it.
I will _definitely_ do something to generate that code
automatically, just as we have leex and yecc and other
tools for generating code.
Post by unknown
The
DSL still maps to functions which needs to access and update these
values, and that code is still painful to write.
Yes, but using a DSL ***means*** that you do not write that code
more than once.
Post by unknown
Your next step is to
think "Great! Let's generate all that code then!". Now you got three
problems, and you better hope to have not made any error when writing
that code generator or you'll waste a lot more time.
I write small-scale task-specific code generators a LOT.
It's not quite as easy as falling off a log, but it's
easier than, say, getting a complex regular expression right.
Yes, I make mistakes when I do this, and yes, I have to test
a fair bit. But most of this is testing I would have had to
do *anyway* and mistakes I would have made *anyway* except
that instead of a mistake being made once, found by one test,
and fixed with a single fix, there would have been dozens of
copies.
Post by unknown
Speaking of time,
by the time you get to that point the PHP developer has already long
finished his bug-free implementation of the same code and is moving on
to other tasks.
Does there exist such a thing as a bug-free implementation of
anything in PHP?

In all seriousness, I use small-scale code generation BECAUSE
IT SAVES ME TIME. Coding time, testing time, debugging time.
Post by unknown
That's still besides the point. If it's not Character.inventory it's
State.character and State.inventory. Doesn't make updating any easier.
Again, I think we have strayed from the original path,
which had nothing to do with updating and everything to
do with the perceived verbosity of Person#person.name.

If you want ease of updating, there's no shame in using F#.
unknown
2013-01-27 03:07:02 UTC
Permalink
LFE is still very much alive! So is Joxa. LFE is much closer to vanilla Erlang in details and properties, this was always a goal. Using it "feels" more Erlangy and it maps more directly onto vanilla Erlang/OTP. In my opinion anyway.

Robert

----- Original Message -----
From: "Raoul Duke" <raould>
To: "erlang-questions Questions" <erlang-questions>
Sent: Friday, 25 January, 2013 11:37:24 PM
Subject: Re: [erlang-questions] If you are homesick for object.selector
please contribute to getting LFE back in motion.
$0.02,
sincerely.
_______________________________________________
erlang-questions mailing list
erlang-questions
http://erlang.org/mailman/listinfo/erlang-questions
unknown
2013-01-27 08:13:32 UTC
Permalink
While I have no idea how the Erlang parsing process works, I assume it
would not be very hard to write a pre-processor that does the following;
1. parse all code for occurrences of record assignments. (i.e.
Person#person)
2. replace all occurrences of the Variable + "." with
Variable#typeFromScope.) (i.e. replace "Person.[somevar]" with
Person#person.somevar.
Why do you assume that?
The preprocessor would have to do more work than the normal
compiler does.

-record(foo, {a}).
-record(bar, {a}).

f(X) -> X#???.a.

There isn't any type in scope. And this is far from
unusual in Erlang code.
If you did forget to mention your type somewhere, compilation would still
fail (which is what it should do IMO).
Most of the frustration probably hides in the fact that the compiler
should
be able to derive that info from the code, as it has been mentioned
before.
Should be able to derive it? Please describe the algorithm.

I used to be an ML fan, and like Haskell a lot.
But there is one phenomenon common to programming
languages with type inference, unless you put a _lot_
of work into error reporting. This is where a tiny
change to a module in one place (like, for example,
removing one call to a function, leaving others) causes
an error report somewhere else in the module (like the
compiler no longer being able to disambiguate a field).

These days we do have the Dialyzer, but it is an _optional_
tool, and it wasn't designed for this particular task.

I honestly don't see what's so bad about putting the
record name in the selector. It was common practice in
Lisp-family languages to use things like
(set-circle-area! my-circle (* (circle-area my-circle) 2))
For that matter, look at C structs like 'struct tm' with its
tm_sec, tm_min, tm_hour. tm_mday &c fields.
unknown
2013-01-27 10:33:40 UTC
Permalink
-record(foo, {a,b,c}).
-record(bar, {a,x,y}).
sum(X#foo) -> X.a+X.b+X.c;
sum(X#bar) -> X.a+X.x+X.y.
Weird. Are you suggesting a new syntax <variable>#<record name>
which is like <variable>=#<record name>{}?

I can't help feeling that

sum(#foo{a=A, b=B, c=C}) -> A+B+C;
sum(#bar{a=A, x=X, y=Y}) -> A+X+Y.

is superior. In ML, I would write

datatype thingy
= Foo of {a : int, b : int, c : int}
| Bar of {a : int, x : int, c : int}

fun sum (Foo {a=a, b=b, c=c}) = a+b+c
| sum (Bar {a=a, x=x, y=y}} = a+x+y

and pretty much the same thing in Haskell.
In functional languages, I expect to use field names
in patterns and not elsewhere.

If you pick up all the fields you want in one pattern
match, you write the record name once and only once.
anotherSum(X) ->
First = X#foo.a,
Middle = X.b,
Last = X.c,
First+Middle+Last.
Yes, but again, why go out of your way to avoid
a pattern match? The idiomatic way to do this is

another_sum(#foo{a = First, b = Middle, c = Last}) ->
First + Middle + Last.

When I devised frames I tried rewriting some fairly
large chunks of existing code using frame notation,
and a _very_ helpful first step was pushing field
accesses back into pattern matching. As a _reader_
of other people's code, I found it _extremely_ helpful
to see _all_ the fields being picked up mentioned in
one place.
So the preprocessor would only infer record info when it is available.
Yes, but "available" is the magic word, isn't it?
The case where a variable is annotated with a record name (and
X#foo is not currently legal Erlang syntax) is straightforward,
but what about
anotherSum(X) ->
First = f(X)#foo.a,
Middle = f(X).b,
Last = f(X).c,
First+Middle+Last.
where to a human reader who has seen f/1 it is obvious that
f/1 always returns the same kind of thing. A *local* check
by a preprocessor is not going to catch this. You need some
sort of type check for at least a whole module.

I am NOT saying that it cannot be done.
I am NOT saying that it should not be done.

I *AM* saying that the hard work of devising an effective
(abstract) algorithm that CAN do whatever the task is should
be done by the people who want the feature. And simplistic
hacks are never going to be satisfactory long term because
people will expect whatever the algorithm accomplishes to
_make sense to them_. And that means that if X#foo works,
then element(N,X)#foo should work, and X#zoo.ick#foo should
work, and if f/1 is "obviously" safe, f(X)#foo should work.
When the algorithm break down, it should be clear to a
programmer _why_ it broke down and what to do about it.
Post by unknown
Should be able to derive it? Please describe the algorithm.
See above
I did _look_ above, but did not _see_ it because you have not
described an algorithm. A sample input output pair or two is
not a description of an algorithm.

Describe an algorithm. Write an EEP. Some EEPs get adopted.
Some get implemented by third parties who like the idea.
unknown
2013-01-28 01:23:19 UTC
Permalink
----- Original Message -----
From: "Richard O'Keefe" <ok>
This is _so_ on-topic...
http://thedailywtf.com/Articles/Ancestors.aspx
Think how much more difficult to read it would have been if you had to include the record names. :-)

Robert
unknown
2013-01-28 01:57:18 UTC
Permalink
On Sun, Jan 27, 2013 at 7:23 PM, Robert Virding
Post by unknown
----- Original Message -----
From: "Richard O'Keefe" <ok>
This is _so_ on-topic...
http://thedailywtf.com/Articles/Ancestors.aspx
Think how much more difficult to read it would have been if you had to include the record names. :-)
For the benefit of those who didn't click the link, it contains this
function in C#:

private void MouseMove(object sender, MouseEventArgs e)
{
(sender as PictureBox).Parent.Parent.Parent.Parent.Parent.GetType();
}

After seeing that, I'm convinced Erlang record syntax is one the
language's best features. If other languages had such a tax, this sort
of thing would be held in check.

Call it a sin tax.

Get it?

Garrett
unknown
2013-01-28 17:08:27 UTC
Permalink
Post by unknown
On Sun, Jan 27, 2013 at 7:23 PM, Robert Virding
Post by unknown
----- Original Message -----
From: "Richard O'Keefe" <ok>
This is _so_ on-topic...
http://thedailywtf.com/Articles/Ancestors.aspx
Think how much more difficult to read it would have been if you had to include the record names. :-)
For the benefit of those who didn't click the link, it contains this
private void MouseMove(object sender, MouseEventArgs e)
{
(sender as PictureBox).Parent.Parent.Parent.Parent.Parent.GetType();
}
After seeing that, I'm convinced Erlang record syntax is one the
language's best features. If other languages had such a tax, this sort
of thing would be held in check.
Call it a sin tax.
Except that's completely different from what we'd like to have.

* We do not want a parent() mechanism.
* We do not want pointers or references.
* We do not want to be able to call functions.

Also note that with regards to Erlang, it's *not* syntax that prevents
this kind of behavior, but processes and message passing. Your process
can only handle so much.

We just need a data structure and associated syntax that's convenient
for semi-deep data structures, where the fields are clearly defined
(like a record), except field resolution would be performed at runtime
to allow chaining and thus easier pattern match and/or modification. And
ironically it could also easily solve the record upgrade problem,
because you'd have the fields at runtime.

Data manipulation is something that can make or break projects, and is
the reason why I stopped one of mine, because all the solutions you can
think of are light years away of what can be achieved with very little
language support.

Of course, language support means first acknowledging there is indeed a
problem, and I am not surprised to hit walls here, especially in the
"you just need functions" crowd (who don't seem to be aware of how nice
pattern matching in function clauses and guards are). So I'll experiment
on my end for a while and if it turns out that it works I might just use
this new language for the previously mentioned project. That'd certainly
motivate me enough to reboot it.

Have a nice day.
--
Lo?c Hoguin
Erlang Cowboy
Nine Nines
http://ninenines.eu
unknown
2013-01-28 17:40:51 UTC
Permalink
Post by unknown
Post by unknown
On Sun, Jan 27, 2013 at 7:23 PM, Robert Virding
Post by unknown
----- Original Message -----
From: "Richard O'Keefe" <ok>
This is _so_ on-topic...
http://thedailywtf.com/Articles/Ancestors.aspx
Think how much more difficult to read it would have been if you had to
include the record names. :-)
For the benefit of those who didn't click the link, it contains this
private void MouseMove(object sender, MouseEventArgs e)
{
(sender as PictureBox).Parent.Parent.Parent.Parent.Parent.GetType();
}
After seeing that, I'm convinced Erlang record syntax is one the
language's best features. If other languages had such a tax, this sort
of thing would be held in check.
Call it a sin tax.
Except that's completely different from what we'd like to have.
* We do not want a parent() mechanism.
* We do not want pointers or references.
* We do not want to be able to call functions.
Also note that with regards to Erlang, it's *not* syntax that prevents this
kind of behavior, but processes and message passing. Your process can only
handle so much.
We just need a data structure and associated syntax that's convenient for
semi-deep data structures, where the fields are clearly defined (like a
record), except field resolution would be performed at runtime to allow
chaining and thus easier pattern match and/or modification. And ironically
it could also easily solve the record upgrade problem, because you'd have
the fields at runtime.
Isn't this close to frames? I'm somehow under the impression that
Ericsson has a "maps" (or similarly named feature) that's near
release.

Unless I've missed something, perhaps a status update on the "frames"
problem might bring this thread to a happier conclusion.
Post by unknown
Data manipulation is something that can make or break projects, and is the
reason why I stopped one of mine, because all the solutions you can think of
are light years away of what can be achieved with very little language
support.
Of course, language support means first acknowledging there is indeed a
problem, and I am not surprised to hit walls here, especially in the "you
just need functions" crowd (who don't seem to be aware of how nice pattern
matching in function clauses and guards are). So I'll experiment on my end
for a while and if it turns out that it works I might just use this new
language for the previously mentioned project. That'd certainly motivate me
enough to reboot it.
I still think you want a relational model for your gaming use case.
SQLite + memory db FTW!

Garrett
unknown
2013-01-28 18:49:18 UTC
Permalink
Post by unknown
Post by unknown
Post by unknown
On Sun, Jan 27, 2013 at 7:23 PM, Robert Virding
Post by unknown
----- Original Message -----
From: "Richard O'Keefe" <ok>
This is _so_ on-topic...
http://thedailywtf.com/Articles/Ancestors.aspx
Think how much more difficult to read it would have been if you had to
include the record names. :-)
For the benefit of those who didn't click the link, it contains this
private void MouseMove(object sender, MouseEventArgs e)
{
(sender as PictureBox).Parent.Parent.Parent.Parent.Parent.GetType();
}
After seeing that, I'm convinced Erlang record syntax is one the
language's best features. If other languages had such a tax, this sort
of thing would be held in check.
Call it a sin tax.
Except that's completely different from what we'd like to have.
* We do not want a parent() mechanism.
* We do not want pointers or references.
* We do not want to be able to call functions.
Also note that with regards to Erlang, it's *not* syntax that prevents this
kind of behavior, but processes and message passing. Your process can only
handle so much.
We just need a data structure and associated syntax that's convenient for
semi-deep data structures, where the fields are clearly defined (like a
record), except field resolution would be performed at runtime to allow
chaining and thus easier pattern match and/or modification. And ironically
it could also easily solve the record upgrade problem, because you'd have
the fields at runtime.
Isn't this close to frames? I'm somehow under the impression that
Ericsson has a "maps" (or similarly named feature) that's near
release.
Unless I've missed something, perhaps a status update on the "frames"
problem might bring this thread to a happier conclusion.
Close. But not quite (at least in its current form).

Here we are talking about a data structure with fixed fields, like
records, which allows amongst other things type checking (dialyzer and
runtime).

Frames would be "better than nothing" but at the last EUC the only thing
related was a benchmark of hash implementations to see which one is best
for eventual inclusion. Sounds like it's the last thing that should be
done though, make it work, make it pretty, make it fast. Many people
would be fine with just the first two (and that's what I'll do in my
experiments).
Post by unknown
Post by unknown
Data manipulation is something that can make or break projects, and is the
reason why I stopped one of mine, because all the solutions you can think of
are light years away of what can be achieved with very little language
support.
Of course, language support means first acknowledging there is indeed a
problem, and I am not surprised to hit walls here, especially in the "you
just need functions" crowd (who don't seem to be aware of how nice pattern
matching in function clauses and guards are). So I'll experiment on my end
for a while and if it turns out that it works I might just use this new
language for the previously mentioned project. That'd certainly motivate me
enough to reboot it.
I still think you want a relational model for your gaming use case.
SQLite + memory db FTW!
Half of this data is temporary to the current session. The other half is
tied to the first half, and only needs to be retrieved and saved at key
intervals. A relational database fits the storage of the permanent data.
It however again only complexifies the manipulation. It would also
likely not scale much. A game has a lot of things happening per player
and you need one or the other value available for use or to send it to
the client when needed and not 2 seconds later.

But regardless, you're still just proposing solutions that increase the
complexity of the work one has to do. I know there's currently no good
solution for this in Erlang, you don't need to convince me.
--
Lo?c Hoguin
Erlang Cowboy
Nine Nines
http://ninenines.eu
unknown
2013-01-28 19:04:36 UTC
Permalink
Post by unknown
Post by unknown
Post by unknown
Post by unknown
On Sun, Jan 27, 2013 at 7:23 PM, Robert Virding
Post by unknown
----- Original Message -----
From: "Richard O'Keefe" <ok>
This is _so_ on-topic...
http://thedailywtf.com/Articles/Ancestors.aspx
Think how much more difficult to read it would have been if you had to
include the record names. :-)
For the benefit of those who didn't click the link, it contains this
private void MouseMove(object sender, MouseEventArgs e)
{
(sender as
PictureBox).Parent.Parent.Parent.Parent.Parent.GetType();
}
After seeing that, I'm convinced Erlang record syntax is one the
language's best features. If other languages had such a tax, this sort
of thing would be held in check.
Call it a sin tax.
Except that's completely different from what we'd like to have.
* We do not want a parent() mechanism.
* We do not want pointers or references.
* We do not want to be able to call functions.
Also note that with regards to Erlang, it's *not* syntax that prevents this
kind of behavior, but processes and message passing. Your process can only
handle so much.
We just need a data structure and associated syntax that's convenient for
semi-deep data structures, where the fields are clearly defined (like a
record), except field resolution would be performed at runtime to allow
chaining and thus easier pattern match and/or modification. And ironically
it could also easily solve the record upgrade problem, because you'd have
the fields at runtime.
Isn't this close to frames? I'm somehow under the impression that
Ericsson has a "maps" (or similarly named feature) that's near
release.
Unless I've missed something, perhaps a status update on the "frames"
problem might bring this thread to a happier conclusion.
Close. But not quite (at least in its current form).
Here we are talking about a data structure with fixed fields, like records,
which allows amongst other things type checking (dialyzer and runtime).
Frames would be "better than nothing" but at the last EUC the only thing
related was a benchmark of hash implementations to see which one is best for
eventual inclusion. Sounds like it's the last thing that should be done
though, make it work, make it pretty, make it fast. Many people would be
fine with just the first two (and that's what I'll do in my experiments).
Post by unknown
Post by unknown
Data manipulation is something that can make or break projects, and is the
reason why I stopped one of mine, because all the solutions you can think of
are light years away of what can be achieved with very little language
support.
Of course, language support means first acknowledging there is indeed a
problem, and I am not surprised to hit walls here, especially in the "you
just need functions" crowd (who don't seem to be aware of how nice pattern
matching in function clauses and guards are). So I'll experiment on my end
for a while and if it turns out that it works I might just use this new
language for the previously mentioned project. That'd certainly motivate me
enough to reboot it.
I still think you want a relational model for your gaming use case.
SQLite + memory db FTW!
Half of this data is temporary to the current session. The other half is
tied to the first half, and only needs to be retrieved and saved at key
intervals. A relational database fits the storage of the permanent data. It
however again only complexifies the manipulation. It would also likely not
scale much. A game has a lot of things happening per player and you need one
or the other value available for use or to send it to the client when needed
and not 2 seconds later.
I'm talking about 1 in-memory db per process. I have no idea how this
would perform -- I'm *mainly* trying to see how long we can make this
thread :)

Nonetheless, if I had a complex data structure that was subject to
change (new features, etc.) I'd be tempted to use a relational model.
Erlang + native SQLite bindings might be quite fast -- I have no idea,
but I'd give it a try and measure.

Of course then you'd *really* need a functional facade -- and how
beautiful would that be?

Garrett
unknown
2013-01-29 00:23:56 UTC
Permalink
Speaking of alternative models, one approach is to move
from thinking of

<thing>
::= <scalar value>
| [{<key>,<thing>]

where you are thinking of a thing as a tree with edges
labelled by keys and leaves labelled with scalars, to

<thing>
::= finite map [<key>] -> <scalar value>

for which an interface like

thing_has(Thing, Path)
thing_get(Thing, Path)
thing_get(Thing, Path, Default)
thing_put(Thing, Path, Value)
thing_add(Thing, Path, Value)
thing_rem(Thing, Path)

makes sense. This thing could really be a tree underneath,
or it could be a dictionary with paths as keys and leaves
as values, or it could be some sort of factored representation.
Or it could be a process, with the paths being used as keys in
that process's dictionary.

It may _look_ like a duck; it may _quack_ like a duck;
but it's _really_ a Psychon.
( http://en.wikipedia.org/wiki/Maya_(Space:_1999) )

Out of the many things that are not clear to me, one of them
is a typical total number of paths relevant to one of these
game characters we have heard so much and seen so little of.

At some point, it would make sense to annoint one dictionary
_interface_ and provide special brief syntax for using it
unknown
2013-01-29 00:07:39 UTC
Permalink
Frames would be "better than nothing" but at the last EUC the only thing related was a benchmark of hash implementations to see which one is best for eventual inclusion. Sounds like it's the last thing that should be done though, make it work, make it pretty, make it fast. Many people would be fine with just the first two (and that's what I'll do in my experiments).
The frames paper actually explains why hash tables are the *wrong* way to
implement them and presents a very lightweight (and empirically fast
_enough_) implementation technique.
unknown
2013-01-28 03:55:18 UTC
Permalink
Post by unknown
Post by unknown
http://thedailywtf.com/Articles/Ancestors.aspx
Think how much more difficult to read it would have been if you had to include the record names. :-)
Yeah, it might have been hard enough to _write_ that the
original programmers might have _thought_. Well, one can hope.
unknown
2013-01-28 13:18:38 UTC
Permalink
There was an even better one mentioned in the test:

if(hasrating)
{
thechkbox = currRating[0].parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.children(2).children(0).children(0)
thechkbox.disabled = false;
}

:-)

----- Original Message -----
From: "Garrett Smith" <g>
To: "Robert Virding" <robert.virding>
Cc: "Richard O'Keefe" <ok>, "erlang-questions Questions" <erlang-questions>
Sent: Monday, 28 January, 2013 2:57:18 AM
Subject: Re: [erlang-questions] If you are homesick for object.selector
On Sun, Jan 27, 2013 at 7:23 PM, Robert Virding
Post by unknown
----- Original Message -----
From: "Richard O'Keefe" <ok>
This is _so_ on-topic...
http://thedailywtf.com/Articles/Ancestors.aspx
Think how much more difficult to read it would have been if you had
to include the record names. :-)
For the benefit of those who didn't click the link, it contains this
private void MouseMove(object sender, MouseEventArgs e)
{
(sender as
PictureBox).Parent.Parent.Parent.Parent.Parent.GetType();
}
After seeing that, I'm convinced Erlang record syntax is one the
language's best features. If other languages had such a tax, this
sort
of thing would be held in check.
Call it a sin tax.
Get it?
Garrett
unknown
2013-01-28 16:16:07 UTC
Permalink
On Mon, Jan 28, 2013 at 7:18 AM, Robert Virding
Post by unknown
if(hasrating)
{
thechkbox = currRating[0].parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.children(2).children(0).children(0)
thechkbox.disabled = false;
}
:-)
if (hasrating)
{
thechkbox = currRating[0].firstChildOfFirstChildOfThirdChildOfParentOfParentOfParentOfParentOfParentOfParent();
thechkbox.disabled = false;
}

--
Evan Miller
http://www.evanmiller.org/
unknown
2013-01-28 19:00:53 UTC
Permalink
Lol, excellent :)

Sent from my iPhone
Post by unknown
On Mon, Jan 28, 2013 at 7:18 AM, Robert Virding
Post by unknown
if(hasrating)
{
thechkbox = currRating[0].parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.children(2).children(0).children(0)
thechkbox.disabled = false;
}
:-)
if (hasrating)
{
thechkbox = currRating[0].firstChildOfFirstChildOfThirdChildOfParentOfParentOfParentOfParentOfParentOfParent();
thechkbox.disabled = false;
}
--
Evan Miller
http://www.evanmiller.org/
_______________________________________________
erlang-questions mailing list
erlang-questions
http://erlang.org/mailman/listinfo/erlang-questions
unknown
2013-01-29 00:08:52 UTC
Permalink
Post by unknown
if (hasrating)
{
thechkbox = currRating[0].firstChildOfFirstChildOfThirdChildOfParentOfParentOfParentOfParentOfParentOfParent();
thechkbox.disabled = false;
}
No, it would be something like
if (has_rating) ratable_part().disable_checkbox();
Loading...