help using "aggregate"

So, I have two scripts that run concurrently, all the time, and they both, at various times, require access to the same data, and they save it.

For a while I've just been banking on the brevity of the execution time and hoping that they never try to read/write at the same time, but it's come time to actually enforce that...

What I'm using to achieve this are the following functions:
Code:
aggregate checkOut(string resourceName){
 aggregate data;
 file_to_map("resources.txt",resources);
 while ((resources[resourceName]!="")&&(resources[resourceName]!=__FILE__)) waitq(1);
 resources[resourceName]=__FILE__;
 map_to_file(resources,"resources.txt");
 file_to_map(resourceName,data);
 return data;
}

aggregate update(string resourceName){
 aggregate data;
 file_to_map(resourceName,data);
 return data;
}

string commit(aggregate data, string resourceName){
 file_to_map("resources.txt",resources);
 string owner=resources[resourceName];
 if (owner==__FILE__){
  map_to_file(data,resourceName);
  resources[resourceName]="";
  map_to_file(resources,"resources.txt");
 }
 return owner;
}

string commit(string resourceName){
 file_to_map("resources.txt",resources);
 string owner=resources[resourceName];
 if (owner==__FILE__){
  resources[resourceName]="";
  map_to_file(resources,"resources.txt");
 }
 return owner;
}

This code alone generates no errors... until I try to use it.
I have a structure defined like this:
Code:
record userinfo{
 int userid;
 string nick;
 boolean[string] multis;
 int gender;//see gengers[] definition comments
 int flags;//see flag bits
 string[string] buffpacks;
 int[int] buffs;
 float lastMath;
 string lastTime;
 string lastTrigger;
 int donated;
 int wallet;
};
userinfo[string] userdata;

and attempting userdata=checkOut("userdata.txt"); I get an error:
Cannot store aggregate in userdata of type userinfo [string] (login.ash, line 31)

Any idea what's going on here? Or do I just not understand how "aggregate" works?
 
Last edited:

Bale

Minion
Well, it would help me to be specific if I knew which line was 31. I don't think you're sharing the whole script so I won't even try to guess. I'll just give you a general answer:

You're mixing datatypes. You cannot store an aggregate in a variable of a different type, just as you cannot store a string in a variable defined as int. Different aggregates are different types.
 
Well, I was hoping to be able to use aggregate so that I could load different types of map, note that I use file_to_map with just a vague "aggregate" and then return that.

Line 31 is
userdata=checkOut("userdata.txt");

I thought aggregate was just an umbrella for "any map" and not anything specific... if so then how and what is it used for?
 

jasonharper

Developer
The only use for 'aggregate' is for parameters that will be passed on to a built-in function that works on arbitrary maps - clear(), file_to_map(), and map_to_file() are the only ones I can think of. It's fundamentally impossible to retrieve any entries from an 'aggregate' in ASH because the compiler has no idea of the data types involved.
 

Bale

Minion
Ah! So that's what you were trying to do.

aggregate can only be used as a parameter in a function in which case it is matched to whatever aggregate value it was called with. This is best exemplified by how it is used in zlib's load_current_map() function. I'll copy-paste that here as an example.

Code:
// loads specified map file either from disk or from Map Manager if an updated map is available (checks once daily)
boolean load_current_map(string fname, aggregate dest) {
   file_to_map(fname+".txt",dest);
   string curr = get_property("map_"+fname+".txt");
   if (contains_text(curr,today_to_string())) return (count(dest) > 0);
   string rem = visit_url("http://zachbardon.com/mafiatools/autoupdate.php?f="+fname+"&act=getver");
   if (contains_text(curr,rem) && count(dest) > 0) {
      set_property("map_"+fname+".txt",rem+", checked "+today_to_string());
      return vprint("You have the latest "+fname+".txt.  Will not check again today.",3);
   }
   vprint("Updating "+fname+".txt from '"+curr+"'...",1);
   if (!file_to_map("http://zachbardon.com/mafiatools/autoupdate.php?f="+fname+"&act=getmap",dest) || count(dest) == 0)
      return vprint("Error loading "+fname+".txt from the Map Manager.","red",-1);
   map_to_file(dest,fname+".txt");
   set_property("map_"+fname+".txt",rem+", checked "+today_to_string());
   return vprint("..."+fname+".txt updated.",1);
}

Note that this function works only because the specific aggregate type is defined by the parameter with which it is called. So you'd use it like...

Code:
 int userid;
 string nick;
 boolean[string] multis;
 int gender;//see gengers[] definition comments
 int flags;//see flag bits
 string[string] buffpacks;
 int[int] buffs;
 float lastMath;
 string lastTime;
 string lastTrigger;
 int donated;
 int wallet;
};
userinfo[string] userdata;

boolean load_current_map("resources", userdata)

Edit: Ninja'ed by jason. That's only because I spent time putting together an example. :p
 
So, I still can do it, but I have to pass it as a parameter and not as a return value... shmucks I really like the equals operator. Thanks!
 

zarqon

Well-known member
I've wished from time to time that we could also foreach "aggregates". Would allow us to make pseudo-stringlists.
 

jasonharper

Developer
I've tried to modify 'foreach' so that it would treat an aggregate as if it were an aggregate[string] map, so you could iterate over it, recursively if needed. It turns out that this road leads only to madness; the compiler can't tell whether the foreach variables are supposed to receive keys or values from the map, so you still end up unable to actually retrieve any data from the aggregate.

The only alternative I can think of would be a built-in function that would take an aggregate and return an array of records, containing stringified keys & values for each entry.
 

zarqon

Well-known member
Yeah, going down the typeless road with a typed language is a pretty good way to go insane, I'd imagine.

I wrote up some stuff a while back when I was considering adding a kind of 'stringlist to ZLib:

PHP:
string map_to_strlist(aggregate a) {        // for single-index maps only!
   buffer res;
   boolean middle;
   foreach i in a {
      if (middle) res.append(", ");
       else middle = true;
      res.append(to_string(a[i]));
   }
   return res;
}
aggregate strlist_to_map(strlist l) { return split_string(l,", "); }

string detect_type(strlist s) {
   boolean[string] types = $strings[boolean,int,float,item,location,monster,element,familiar,skill,effect,stat,class];
   foreach i,str in strlist_to_map(s) {
      foreach t in types {
         if (normalized(str,t) == "none" && str != "none") continue;
         if (normalized(str,t) == "0" && str != "0") continue;

      }
      
   }
   return "string";    // looks like I never finished this function
}

int list_match(strlist haystack, string needle, string type) {
   foreach i,b in split_string(haystack,", ")
      if (normalized(b,type) == normalized(needle,type)) return i;
   return -1;
}
int list_match(strlist haystack, boolean needle) { return list_match(haystack,to_string(needle),"boolean"); }
int list_match(strlist haystack, int needle) { return list_match(haystack,to_string(needle),"int"); }
int list_match(strlist haystack, float needle) { return list_match(haystack,to_string(needle),"float"); }
int list_match(strlist haystack, item needle) { return list_match(haystack,to_string(needle),"item"); }
int list_match(strlist haystack, location needle) { return list_match(haystack,to_string(needle),"location"); }
int list_match(strlist haystack, monster needle) { return list_match(haystack,to_string(needle),"monster"); }
int list_match(strlist haystack, element needle) { return list_match(haystack,to_string(needle),"element"); }
int list_match(strlist haystack, familiar needle) { return list_match(haystack,to_string(needle),"familiar"); }
int list_match(strlist haystack, skill needle) { return list_match(haystack,to_string(needle),"skill"); }
int list_match(strlist haystack, effect needle) { return list_match(haystack,to_string(needle),"effect"); }
int list_match(strlist haystack, stat needle) { return list_match(haystack,to_string(needle),"stat"); }
int list_match(strlist haystack, class needle) { return list_match(haystack,to_string(needle),"class"); }

Of course, it didn't work, but I wanted to see if it was worth a feature request, and it was easier to see when I wrote it out as though I could do what I wanted. The really crazy bit was a function returning an aggregate. The idea was for strlist_to_map() to take a strlist (which is just a string) and convert it to a map of <type>[int], like split_string() but for each type.

I suppose that's a reasonable feature request -- a split_string() for each type (or accepting a type parameter, but that would mean a single function with multiple return types again, so probably not).

Also cool would be a $type[] type, including "int, string, coinmaster, monster, element" etc. But I digress.
 
Top