map/record help

Okay, so I'm in the process of converting
Code:
int[string,string,string,string,string] allInfo;
into something more malleable, namely
Code:
record piece{
 string name;
 string img;
 string link;
 int r;
};
piece[string,string] newInfo;
via
Code:
 piece p;
 foreach t,i,n,l,x in allInfo{
  p.name=n;
  p.link=l;
  p.image=i;
  p.r=0;
  newInfo[t,x]=p;
 }
There's no overlap caused by [t,x] because for each allInfo[string] there is only one key in each sub-aggregate.
My problem is, after running into this, I have a whole bunch of [t,x] pairs with the same record data.

I'm guessing that the assignment newInfo[t,x]=p is acting more like a pointer to p than actually moving the data from the record into a new piece of memory; my problem is that I don't know how to avoid that. Clues?
 
Took my pointer idea and ran with it, found "new".

While I'm glad I fixed my issue, this behavior is extremely unintuitive and incongruous with all other data operations I've come across in mafia, and should probably be highlighted (I really want this word to be highlit) on the wiki page under Records.
 

Winterbay

Active member
I think you might need to exchange "newInfo[t,x] = p;" with:
Code:
newInfo[t,x].name = p.name;
newInfo[t,x].link = p.link;
newInfo[t,x].image = p.image
newInfo[t,x].r = p.r;

But I'm not the master of records so I could be wrong :)

Edit: And ninjad by yourself. I was thinking about new, but was unsure of how to use it as well :)
 

jasonharper

Developer
Code:
 piece p;
 foreach t,i,n,l,x in allInfo{
  p.name=n;
  p.link=l;
  p.image=i;
  p.r=0;
  newInfo[t,x]=p;
 }
Exactly one record exists in this code, the one created by default at the declaration of 'p'. Storing something in a map never copies it, so all of the map elements end up being that same record, with whatever field values the final iteration of the loop assigned to it. If you don't find this behavior intuitive, you need to file a bug report on your intuition.

There's nothing specific to records going on here: any mutable data type (which also includes maps, arrays, and buffers) would exhibit the same behavior. Actually, the behavior applies to ALL data types; it's just that with most of them, there's no way to observe whether the original or a copy is being stored in a map, because there are no operations that change the object's value.
 

StDoodle

Minion
Yeah, I've struggled with this one too. As a non-programmer it isn't all that intuitive how it works, but if you think on it a bit it does start to make sense. In general, what you want to do when creating new records is use either the built-in new command or a customized version of your own (if there are lots of defaults that differ from the primitive type defaults; but even this should probably make use of new internally). So, in pseudo-code:
Code:
foreach setOfInfo {
   mapOfRecords[key] = new record(field, field...);
}
 

heeheehee

Developer
Staff member
Yet another fix would be to swap the first two lines. That way, you're creating a new record with each iteration.
 
Exactly one record exists in this code, the one created by default at the declaration of 'p'. Storing something in a map never copies it, so all of the map elements end up being that same record, with whatever field values the final iteration of the loop assigned to it. If you don't find this behavior intuitive, you need to file a bug report on your intuition.

There's nothing specific to records going on here...
it's just that with most of them, there's no way to observe whether the original or a copy is being stored in a map...

Code:
 int[int] m;
 int i=1;
 m[1]=i;
 i=2;
Exactly one instance of i exists in this code, but changing i to 2 doesn't change m[1]. The value is copied, not the memory location. So to say it does this with ALL data types is incorrect.
You contradict yourself by saying that storing something in a map never copies it, then you go on to say that there's no way to tell which is occurring. Since this doesn't happen with ints, floats, strings, or any of the KoL-specific $types, I'd say that is indeed special to records (and probably maps as well, though I haven't tested)
 

Theraze

Active member
I think his comment was specifically regarding THAT code... not all possible ways to use code. In which case, he was correct...
 
Then he shouldn't have said all data types, he should have said records. The same loop with a different data type wouldn't behave the same, it'd copy the value and each element of the map would point to a different value in the end.
 

jasonharper

Developer
I stand by exactly what I said. In your supposed counterexample, you're changing the value of 'i', not the value of 2, so it's not at all equivalent to the original code with a single record that's being modified. Or in other words, "Exactly one instance of i exists in this code" isn't correct; 'i' holds two distinct values over its lifetime, and it's the one in effect at the time it was used that became the map value.

Or in other other words, these two forms of assignment have a fundamental difference that you seem to be missing:
Code:
someVariable = something;
someRecordVariable.someField = something;
In the 1st form, the variable takes on an entirely new value, unrelated to its previous value.
In the 2nd form, the variable does not change value at all (it still refers to exactly the same record), but an internal change is made within that value.
 
I'll just chalk that up to something Java does then. In my experience a given record is the sum of its parts, and to say "record x=r" is to copy those internal values to a new memory location (a la "int i=n")

My familiarity with records makes each one its own variable, not a pointer to one. So, to me, what mafia is doing with "=record" vs "=record.field" is the different between "=prec" and "=*prec.field" (or "=prec^.field" or "=prec->field" depending on your language of choice), where I was expecting, well, what I typed originally.
 
Last edited:

xKiv

Active member
That *is* how struct copying works in C. However, ASH is based on objectful languages, where you are *always* manipulating *pointers* to structures, not the structures themselves.

BTW, your "a la int i=n" doesn't actually prove anything here - it does exactly the same thing in both paradigms. Pointer to an immutable thing is interchangeable with that thing (as long as you have only one such pointer for each immutable thing, or override your comparison operator to follow the pointer).
 
Last edited:
Pointer to an immutable thing is interchangeable with that thing.

What makes n (or i?) immutable? Or are you referring to the integer value that it (they?) contains? Either way I'm not entirely sure I understand.

I'm trying to toss over a few different interpretations of this in my head and none are making sense.

We're ex-clannies, hit me up in-game (almighty sapling)
 

jasonharper

Developer
Immutable just means that there are no operations in the language that would modify the value. It's a property of the value itself, not the variable referring to the value.
Records are mutable because you can assign to a field: r.f = x;
Maps & arrays are mutable because you can assign to an element: m[k] = x;
Buffers are mutable via several built-in functions: b.append("ix") for example.
Nothing you can do will change the value of an int, string, or other type not listed above. That's an important property, because it allows them to be safely used as keys in a map without having to be copied each time.
 

xKiv

Active member
What jason said - you don't have immutable variables, just values.
OK, you could say a variable is immutable if you declared it as a "const", but that doesn't apply in ASH.

As for cloning/non-cloning ... well .. you just have to know when you are handling the aggregate value itself, and when you are handling a reference to it.
(this is easier to recognize in Simula, which has := for all "clone the value" assignments and :- for "clone the reference" assignments)
 
Top