ArrayLists in ASH? [Discussion]

heeheehee

Developer
Staff member
You actually did "file to string[int]" - i.e., file to map of strings indexed by integer.
Most programs will not notice the difference, although it is (minutely) less efficient under the hood.
(If I were to implement that as a proper array, I'd probably use an ArrayList, then just use `new ArrayValue(lst.toArray())` after populating said list.)

Do we want a native ArrayList datatype in ASH? We have arrays, and IIRC plural typed constants are immutable ArrayLists under the hood.

I don't find myself trying to write high-performance ASH, ever, so I'm not sure it's worth the effort (hence the presence in Scripting Discussion vs a Feature Request bug). Does anyone else?
 

Veracity

Developer
Staff member
Plural typed constants are parsed as ArrayLists but stored as a Java array. To the ASH programmer, they behave as sort of like "boolean [type]". You can use that as the datatype for them, but unlike a map declared like that, there can be multiple instances of the same key.

Code:
boolean [int] ints = $ints[ 1, 2, 3, 4, 3, 2, 1 ];

print( "There are " + count( ints ) + " ints in the plural constant" );
print( "ints[3] = " + ints[3] );
print( "ints[100] = " + ints[100] );

foreach key in ints {
    print( key );
}

Code:
[color=green]> plurals.ash[/color]

There are 7 ints in the plural constant
ints[3] = true
ints[100] = false
1
2
3
4
3
2
1

If we wanted more datatypes, I'd suggest "list [type]" (backed by ArrayList) and "set [type]" (backed by HashSet). Those would be mutable, and the set - unlike a plural typed constant - would not allow duplicates. We'd want a few more operations. We already have count() and contains and remove, but add (for sets) and append and insert (for lists) seem reasonable. We'd need to decide how to represent them when dumping them via file_to_map and map_to_file. They are Composite values, but for a "set", you only care about the keys, and for a "list", you only care about the values.

My "vprops" library lets you declare variables to be "set of type" (backed by "boolean [type]") or "list of type" (backed by "type [int]", where int goes from 0 .. size-1). It uses "1|2|3|4" as the "string" representation of either a set or a list.
 
Last edited:
Do we want a native ArrayList datatype in ASH? We have arrays, and IIRC plural typed constants are immutable ArrayLists under the hood.

My issue was with the immutability. If it weren't for that, I wouldn't have ended up making my own pseudo-list implementation to get more typical array-like behavior.

I'd love a nice ArrayList-like datatype but have also gotten used to workarounds for it.

I have been under the impression that the want for this isn't too wide-spread. But, I'd like it but would feel bad if it were a pain in the butt.
 

Veracity

Developer
Staff member
Adding "list" and "set" would be a fun little project. The hardest part might be coming up with a syntax that is expressive.

Code:
// Current map syntax with map initializer
string [int] xyzzy = { 1 : "one", 10 : "ten" };
print( xyzzy[10] ); // ten
foreach key, value in xyzzy {}

// Current array syntax with array initializer
string [] xyzzy = { "zero", "one", "two" };
print( xyzzy[2] ); // two
foreach key, value in xyzzy {}

// A list of strings with list initializer
list [string] xyzzy = { "zero", "one", "two" };
print( xyzzy[2] ); // two
foreach val in xyzzy {}

// A set of strings with set initializer
set [string] xyzzy = { "zero", "one", "two" };
print( xyzzy contains "two" ); // true
foreach val in xyzzy {}
I like those pretty well. One issue is that if I make "list" and "set" keywords, there are a ton of scripts using those as variable names - including zlib and vprops.

If I don't make them keywords, anywhere that allows either a type or a variable reference could be a little tricky.
Hmm. If those tokens are followed by a "[", assume they are data types, otherwise variable references?

Code:
string [int] list;
list[5] = "abcx";
If they are followed by "[" and then a datatype, assume they are datatypes? Yuck. That's more lookahead than we've ever needed before.

Perhaps put in a warning message if you define a variable named "list" or "set", saying this is a forthcoming reserved word, and allow time for scripts to adapt to the future incompatibility?

Thoughts?
 
I like the initializer list style syntax you've shown. I'm hoping these would be mutable.

I'm guessing the interfaces provided by ArrayList/Set (or the C++ equivalents) would be overkill but a good basis in terms of what built-in functionality may make the most sense.

list/set are good names. A warning message would be nice. There are some defunct scripts but the fix could be done easily enough in this case.

If you want to do the lookahead, great. If it is easier to not to, the warning message and some time (I have no idea what a good amount of time would be) would be good too.
 

heeheehee

Developer
Staff member
For me at least,

* the minimal interface required for a set is insert, contains, remove.
* the minimal interface for a list is iteration (e.g. foreach), indexing (e.g. bracket notation, or .at(index)), insert(index, val), remove(index).

We have existing ASH language analogues for most (if not all) of these.

Are general ASH values hashable? If not, it might be simpler to just use TreeSet (and probably not significantly worse average performance).
 

fronobulax

Developer
Staff member
Looking at the Java API I think I would want size() added to heeheehee's minimum for sets and lists. I'd consider contains() as a useful addition to lists but of mildly less importance.

I think the language should appropriate the keywords set and list. If a warning is given we may run into a social problem in that there are some scripts in use that aren't really being maintained at the published SVN location. The fix can get made but if no one checks them in somewhere then the SVN support in KoLmafia is not as useful.

I wonder if a new ash keyword might help with the transition? Call it useSetLists. If it is present, set and list are reserved words. If it isn't they aren't. It is expected zero or one times per file and its scope is only the code in that file. I think that lets code that uses the feature and code that uses the variable name to be mixed and script writers to opt in. I am perhaps naively believing that there are only a couple places where the parser/interpreter would have to behave differently and those would be simple conditionals.

Of course instead this may be the change that drives us to establish a community provision for orphaned scripts - those that are of use, casually maintained but cannot be checked into the published repository because the owner of the repository is inactive and has not delegated write access.
 

xKiv

Active member
I wonder if a new ash keyword might help with the transition? Call it useSetLists. If it is present, set and list are reserved words. If it isn't they aren't. It is expected zero or one times per file and its scope is only the code in that file.

How about enabling new syntax if the script declares "since r<revision that is known to understand the syntax>"?
 

fronobulax

Developer
Staff member
How about enabling new syntax if the script declares "since r<revision that is known to understand the syntax>"?

I thought about it but I wasn't sure I wanted "since" to become file a file by file setting. As a reformed configuration manager I see KoLmafia and Ash as separate configuration items, and thus potentially with separate version numbers, even though that separation does not exist in practice.

I'm also a little concerned about what happens if someone tries to use a feature newer than setlist but has not adopted the keyword meaning instead of variable names for set and/or list. Do we force them to adopt setlist first? (Which is trivial enough but sometimes people bristle at being told they have to do something :) )
 

heeheehee

Developer
Staff member
I thought about it but I wasn't sure I wanted "since" to become file a file by file setting. As a reformed configuration manager I see KoLmafia and Ash as separate configuration items, and thus potentially with separate version numbers, even though that separation does not exist in practice.

I like the idea of eventual deprecation, and would be in favor of that potentially in conjunction with the since guards in the meanwhile. Or just use Veracity's proposal of using context for list/set without making them fully reserved right away.

I'm also a little concerned about what happens if someone tries to use a feature newer than setlist but has not adopted the keyword meaning instead of variable names for set and/or list. Do we force them to adopt setlist first? (Which is trivial enough but sometimes people bristle at being told they have to do something :) )
It's really not that hard to do a search+replace of set / list. One would hope that if you're actively committing new code, you're also at least running validate script.ash...
 

heeheehee

Developer
Staff member
Looking at the Java API I think I would want size() added to heeheehee's minimum for sets and lists. I'd consider contains() as a useful addition to lists but of mildly less importance.
I think a lot of these have existing analogues. To add to Veracity's examples:

set contains obj
foreach obj in set
remove set[obj];
count(set);

list contains obj
foreach obj in list
remove list[index]
count(list)

add / insert is the only one off the top of my head that would probably require special syntax (or a new function). Polymorphism could mean that we could even use append(aggregate, obj), although I think I'd prefer one of the names add / insert (preferably with the ability to specify index for lists, too).
 

Veracity

Developer
Staff member
I'm planning on working on it this (long holiday) weekend.
I pinged zarqon, asking for his contribution to the discussion, since non-backward-compatible versions of this directly affect his scripts.
Still hoping he responds, before I start spending time on it...
 

zarqon

Well-known member
I quite appreciate your messaging me about this. Unfortunately I won't have time to formulate proper opinions and give a proper response until after the weekend (out of town gigs). Would be nice if it were a holiday weekend over here now as well!

I can say for now that I'd be happy to change the list-handling functions in ZLib to not use the word "list" as a variable. Those functions mainly enable functionality which it looks like this new feature will replace, so the new ASH feature may deprecate that section of ZLib anyway.

More on this after the weekend. Will endeavor to push an update to ZLib renaming the variables tonight.
 

Linknoid

Member
Maybe it's too late to contribute anything to this discussion, so ignore this if the feature is already done.

Is there a reason to create a list type instead of just extending the functionality of arrays to act more like arraylists? From an end-programmer perspective, you can basically treat an arraylist and an array as identical concepts, except arraylist allows resizing. It seems much more elegant to add insert/remove functionality to arrays to make them more like arraylists than to introduce a whole new collection type. And as an added benefit, you don't break anyone's code who uses the word "list". What is the benefit to having two similar collection types when one is simply a superset of the functionality of the other?
 
Top