Make a zero-based version of Snap!

alright, give me 2 days and i'll be done


Most strongly typed languages return -1, because they can't return something sensible like "not found," because they're committed to returning a number. And in particular, the ones descended from C use -1 because Unix system calls use negative integers (not always -1, so they can indicate what sort of error) to report errors.

I don't think any of the descendents of Lisp use negative integers in that way.

I hate to say anything nice about Java, but the really right thing to do about errors is to throw an exception that will stop the program with an appropriate error message unless the programmer explicitly catches the exception.

That's the same with python, and a little bit of javascript. Javascript is weird because many things do throw an error, but many things also just get ignored (like accessing undefined properties). The benefit of how javascript handles getting items from lists because it returns undefined if it can't find the item. Python straight up throws an error.

I prefer throwing an error, because with UNDEFINED you have to check for that explicitly after every procedure call, which slows down both the program itself and, more importantly, programming it. And if you forget one, you get a confusing error somewhere later in the program.

But it should be syntactically easy to catch the errors, e.g., our SAFELY TRY.

(The above is a quote from another topic, but I think it’s more appropriate to further discuss it here)

Even in Snap! for some tasks, e.g. in many 2D operations, 0-based indexing is more suitable than 1-based. The example below is from code I wrote for Advent of Code 2023, day 21; it calculates the index of a node within a list representing a 2D-map from the puzzle input (my implementation of Dijkstra’s shortest path algorithm expects a network to be represented by links referring to consecutive node numbers from 1). I’m hinting at untitled script pic 209, of course.

Also, when working with Snap!’s primitive graphics blocks, you will need to address pixel maps in a similar way,

And what about untitled script pic 208? Suppose you want to convert a very long (perhaps virtual) list to a much shorter bucket list, with a limited number of buckets. Then you’d have to make calculations like:

I’m not saying it’s all such a big deal, and I recognize the advantages of 1-based indexing, but what I am saying is, 0-based indexing is not “bizarre”.

As an alternative for developing an 1-based Snap! fork, I (seriously :smirk:) propose the following functions as primitives:

untitled script pic-6, meaning +1, untitled script pic-7 meaning -1,

and a variety of MOD: untitled script pic-2

or it could be up to the user because in 10.0, you will be able to edit primitives, which you can make the item of block add 1 to the index (if it's a number).

As your code pictures show, this is a fine idea for a library.

But, in defense of "bizarre," I want to focus on your 2D-INDEX block. This looks to me like a perfect illustration of the idea of abstraction. Yes, if a 2D array is represented internally in a certain way, then the implementation will sometimes subtract 1 from an index. But this is none of the user's business. As far as the user knows, the 2D array might be represented internally as a list of lists, in which case there wouldn't be any ROW−1 in the implementation. So, what I meant is, zero-origin indexing is bizarre if it's visible to the user.

Except in C, because its intended "user" isn't a user at all, but rather a systems programmer building something memory-focused such as an operating system kernel or a compiler or a garbage collection library. Those people do need to understand how a cardinal index might be different from the item's ordinal index. They need to understand much harder things, too, such as how parallelism gives rise to critical sections of code that need to be serialized. That's what make the programming projects in an Operating Systems class so notoriously hard to debug; by the time students take this upper division course they take zero-origin indexing in stride.

The tragedy of the present moment in programming languages is that essentially every general-purpose programming language in widespread use is a mod of C, imposing on all programmers a set of design decisions originally made for a special-purpose language. Zero-origin indexing is an example. (These languages also inherit C's plain old mistakes, such as using "=" for assignment. In defense of C, it inherited that mistake from Fortran, which (like Basic) exacerbated the mistake by also using "=" for the equality predicate.) By the way, I said "general-purpose" above to exclude languages such as Mathematica and Prolog, each of which is built around its own super-high-level abstraction.

As I've said in some other thread recently, if for some particular purpose you feel a need to expose zero-origin indexing to users, the right way to do it is to build a zero-origin list Abstract Data Type, which would have a type-tag header allowing you to overlay procedures like ITEM that deal explicitly with indices. As in APL, the header would also include the array's dimensions, so your 2D-INDEX block wouldn't have to take #COLUMNS as an input.

It is, though - warning!: whataboutism :smirk: - when one uses e.g. Javascript minis script pic. AFAIK Snap! offers no built-in abstraction layer enabling users to address elements of a costume by row and column, for example. One might justifiably claim there’s an abstraction gap between high-level primitives such as Javascript minis script pic 2 and relatively low-level pixel manipulation (even though Snap! pixels are themselves abstractions, of course).

I don’t have much of an opinion on the implied disastrous influence of C language. Nor would I, as an ordinary though experienced user, seek to introduce a new data type, as such tends to have far more effects than originally anticipated.

But compiling a library may be a practical approach for now.

An abstract data type, I said -- those are ones introduced by users. Nobody else would have to use them.

Indeed. I would have been happier if PIXELS OF reported a list of rows, each of which would be a list of atomic (and first class) colors. I think the vector of colors we have instead (inherited from JS) is just a compromise for the sake of efficiency.

actually, hold your breath there - we might offer a second way to query pixels from a costume in the future that results in a 3D Matrix of rows-columns-rgb (no alpha), and also lets you generate costumes from such shaped data. This will make it much easier and faster to play with certain signal processing concepts.

You mean, like … ? (I don’t see why you would leave out ⍺)

… but faster, probably :smirk:

And I’ve been thinking of a manipulation function such as:
intermediate level graphics script pic 3
(vaporware, as yet)

Yeah. I think you shouldn't have to give the dimensions as inputs, because (I think Jens doesn't agree with me about this but I'm not sure) a costume should include a header containing its shape (APL ⍴). So users should never have to know the dimensions. But a Pixel, too, which is the thing that'll go in the empty input slots inside the MAPped function, should have a header (that's the wrong word; I'm not committed to it living in front of the datum in a list; maybe it's generated by MAP itself, and contains the indices of that pixel in the costume, which MAP knows even though the user doesn't. Then you could have a block untitled script pic (2) which (with these inputs) would report the Pixel to the southeast of the current Pixel. Maybe even those two inputs would be menus, with entries Left, Same, Right or Down, Same, Up.

But then those functions would have to be translated into something efficient, never to be seen by the user. :~)

I’m not sure if we understabd each other. My intention for this block is actually to apply a transformation, as defined by the ringed argument. on a pixel, a horizontal or vertical series of pixels, or otherwise (square) part of the matrix that is the final argument; ROW(s) and COLUMN(s) refer to the part to be transformed, not to the matrix as a whole, whose dimensions are the length of the upper level list (number of columns) and the length of each sublist (number of rows), respectively. I’ll do some more thinking on this.

You mean, "I'm not sure if you understand me." Thanks for being polite about it. :~)

Now I get it. Yeah, that makes sense, but that means your MAP variant is going to have to come inside a FOR or another MAP or something. Or do you mean that your inputs are the height and width of an active subpicture, rather than the absolute column and row numbers? And you'd then call the function for every appropriate-size subpicture that exists?

You'll have to think about boundary conditions. Jens has examples in which it's helpful to pretend that the picture includes a border of black (RGB=0) pixels, so subpictures that stick out into the border are possible.

On New Year's Eve I thought about my proposed intermediate level graphics script pic 3.
On second thought I don't think it's flexible enough, as it will only work on square cuts of a costume. Instead, I’m now considering the following block:

It may be used to make a square hole in a costume:

… but it may also be used to apply a circular pattern on a costume (poor Alonzo):

The latter is rather complicated, though.

I’m not done thinking yet. Perhaps an alternative approach would be adding / subtracting / mixing / overlaying images?

BTW @bh, you may want to move items 69 or 70 and up to a separate topic on “2D-pixel map” or something.

Nah, the question of zero-origin indexing is closely related to the question of multi-dimensional arrays, since the linear position of point (a.b) in an array is a·width+b in zero-origin, which is the only good reason for it.

About your block, have you considered

? The two functions would take as many inputs as the dimension of the array. You could either make it specifically for 2D arrays or give the array a header giving its shape.

Thanks for the suggestion … however, I don’t get it. :confused:
Could you write a simple 2D-example of its use, perhaps a version of my 2nd script in post #75?

I’m trying to think how this suggestion might work.

BTW I’m not overly enthusiastic about the predicate (2nd input) of @bh’s suggested block) though, as that would imply every element of the matrix meeds to be tested, whereas I strive to create a function that works really fast on a small part of a matrix, like a square rectangle within a larger 2D-matrix (or a rectangular box within a larger 3D-matrix, a hyperbox in 4D, etc.). I found a different, and potentially truly efficient, way to isolate the working zone, alas … this solution involves the use of RESHAPE for 3D-matrices (and up). It strikes me that RESHAPE is apparently so much slower in execution than COLUMNS OF (with the same data), even though these operations seem somewhat alike. Is there an improvement potential?

BTW-2 There’s no need for the array to have a header, its shape is deductable from its structure how it’s going to be processed will be determined by the length of the selection condition’s input list.

What I’ve been looking for is a general way to specify a list of MAP-able callback functions, one for each level of the array. What I want to achieve is that for each pixel (or voxel, or hypervoxel, respectively) all of the following inputs may be utilized:

  1. its value
  2. its coordinates within the working zone (2 coordinates within a rectangle, 3 coordinates within a box, 4 within a hyperbox, …).

In the simplest case, of a 2D-array (rectangle), a pixel’s value and its 2nd coordinate are inputs provided to any callback function by MAP. Its 1st coordinate however is only known at the shallowest (1D) matrix level. E.g. if the function to be implemented is: RGBA × √ (x2 + y2), with RGBA as the pixels value and (x, y) as coordinates within the rectangle, then all I can think of now is something like:

… but that’s not specifiable as a list of two functions (or is it?).

What about a much simpler approach with the helper libraries, to get additional view/attributes from the input data
pixel map script pic (1)
pixel map script pic (4)
pixel map script pic (5)

Used this way
pixel map script pic (3)

pixel map script pic (2)

It's a streamlined version of the
pixel map script pic (7)


BTW: maybe with the enhanced control over the varidic params of the v10, we've got some tools to build the custom HOF?