Array programming

BlitzMax Forums/BlitzMax Programming/Array programming

Yasha(Posted 2016) [#1]
So a while back we had a little discussion about array programming and whether it was a useful concept in languages like BlitzMax. I don't know what other people think, but I think it is.

So anyway building on the suggestions in that thread that we ought to establish a set of array-primitives to enable people to start adopting the style, I've had this sitting around in my Projects folder for some months now:

"arraymax.bmx" (basic sequence and operator types)


"arraymax-basis.bmx" (a basis library of fundamental operators):


Crappy example:


Normally I try to polish these things up a lot more and, like, document them, before making them public - but the reason I'm dumping this half-finished idea out there is because I'm kinda stuck for ideas where to go from here, so it needs some collaboration in the form of suggestions (for more basic operators, for more primitive constructors, for any examples). Problem with a technique that's basically "as fundamental as loops" is that ... well, it's so fundamental that you can't really "present" it as a thing unto itself the way you can with more complex constructs. Help?

What would be nice is if we can build a kind of "standard basis" of array operators and sequence functions that can form a base layer for general-purpose loop-free Max programming going forward. In the long run, I'd like to turn this idea into something useful that helps people write much shorter code. I'd [i]really like to turn it into something that's seen as a "Max primitive" so that this gets accepted as the "easy way to do things" over writing explicit loops (it is technically simpler - one line is simpler than three - but it's obviously unfamiliar right now, so let's change that).


A minimal explanation of the dump above:

- the basic data type is the "Seq". This is an opaque array of values. You can construct it with Seq.Make from an array of numbers, an array of objects, or from a TList. The idea is that the internal representation of the Seq is not so important and you can "shimmer" e.g. an int Seq into an object Seq (you can request a translation of an int/float/object seq into any of the other three types: data may be lost, obviously, depending upon what it actually contains). There's room for more underlying Seq representations if they become useful.

- a Seq supports the fundamental recursion-operators:
--- Map (create a new Seq with each value transformed by the given operator)
--- Each (apply the given operator to each value, don't create a new Seq though)
--- Zip (combine the values in this Seq with those in another, using the given operator, to form an output Seq)
--- Fold ("roll up" the values in this Seq into a single value, starting from 0)
--- FoldR (start from the other end)
--- Unfold (build a Seq up from a single value by repeated application of a SeqBuilder object)
--- Filter (keep only the values in a Seq that are matched to "true" values in a mask Seq)

Operators are objects with a value-processing method (IntFunc, FloatFunc or ObjFunc). Implement these methods to create an operator that can process values in a Seq. Not all operators have to work on all kinds of contained value (e.g. Minus won't work with Objects by default; trying will throw an exception). Operators can be monadic or dyadic. You can compose operators together, and there are convenience constructors to build them from function pointers to save you defining new types for everything. Dyadic operators can also be bound to a value (creating a monadic) or argument-flipped. More ideas for operator convenience functions are definitely wanted.

The Basis is a short library of fundamental BlitzMax operations wrapped up in Ops so you can get started with the basics immediately. It includes:

--- all of the arithmetic operators
--- create instance (of a type identified by a string)
--- get field (identified by string)
--- get element of array (by numeric index; that is, where "BlitzMax array" is the contained type of object in an Object Seq)
--- Asc, Chr, ToString, Print

While composing these together could theoretically do pretty much anything, obviously it would also make more sense to write custom operators for other specific scenarios.

As is evident from the fact that you can apply any operator to a Seq of any underlying type, this is a very dynamic system. Dynamic typing is the order of the day. Static typing is possible with array programming but we don't have the tools to express it in BlitzMax's type system, so I decided to embrace dynamism from the start instead.


This is intended to enable and encourage a highly compact, compositional style of writing. Performance is not a particular priority. This stuff is fast enough in interpreted languages like Python and so on; BlitzMax can easily handle the strain. You can always go back to writing explicit loops if you need performance, but the idea here is to start out by making things easier on the programmer, and fix that problem if/when it arises. (That said, I'd still compile with NoDebug once it's thoroughly tested.)

It's not much code yet. As I said, this is just a starting point; I'm interested in taking suggestions and building it up.


Yasha(Posted 2016) [#2]
I pasted the first file twice and for some reason can't edit the post now (is it too long? didn't hit the char limit). The actual basis file:




Bobysait(Posted 2016) [#3]
In the type "ISeq"
-> Method Map
You've got a "<i>" instead of [i]
I don't why you can't edit the first post, but it seems some data are corrupted.

It runs fine while correcting the bracket.
Whatever, I 'm even not sure to understand what I'm reading in your topic :)

What are you planning to do ?
a kind of script-syntax to replace blitzmax code ?

To be honnest, I feel like the more explicit a language is, the more words you need to remove counter-intuitive senses.
So : too lite codes can be really really hard to understand.