Snap 10.1.0 now has 4 forms of inheritance?

reading the update notes, 10.1.0 calls the new list features OOP 2.0. which form of object inheritance is 1.0?

(this table is incomplete, it's very time consuming to put all the images in and i don't really have the energy to continue it. see my project Objects, environments, and dictionaries for more information on ring scopes.)

list tail list ... ring scope sprite parent
empty empty list empty list call join ring ring a new clone of Turtle sprite
(not really, contains global variables and doesn't work in stage)
new with parent key val in front of parent key val with ... key for parent make new and change parent
new without parent list of pairs list of pairs make new with empty parent make changes to sprite with tell
set item replace item of list replace item of list tell object to set key to val tell object to set key to val
get parent can't
change parent can't replace item ... of list can't tell sprite to set my parent
get basic list difficult variables of variables of
get ring scope ring of

all these have related behaviours:

implicit immutable explicit mutable
list pairs list tail list ...
variables ring scope sprite parent

lists can have any number of tails and may have a ...
ring scopes can have any number of parent scopes and may have a sprite
a sprite can often be treated as a ring scope, it has the sprite local variables and global variables.

i haven't tested how the stage behaves, not sure if it can have a parent.
some of these can also inherit themselves or otherwise loop, i haven't fully tested what.
there's also major performance penalties to a linked list dictionary last i tested. ring scopes / sprites have about the same performance as an array dictionary (a list made without linked list blocks). i haven't tested the performance of the new ... feature, and i'm not sure if linked lists can have an array tail.

going off the release notes for 10.1.1 and 10.1.2, ring scopes seem to interact with lists in some new way i don't know about too.

  • only bind rings fetched from a list to the list as environment if they are accessed by a non-numerical index (OOP 2.0)
  • only bind rings that replace list items to the list as environment if they are referred to by a non-numerical index (OOP 2.0)

This was a bugfix; the way Jens initially did it, lists that weren't intended to be objects but happened to have functions as items implicitly called the function when you accessed it with ITEM. He's using "non-numeric index" as a proxy for "OOP 2.0" because there's no explicit "this is an object" flag.

Yes.

Sprite cloning.

Using dispatch procedures with persistent local variables (what you call ring scope) doesn't have a number (OOP n.0) because we didn't use lexical scope specifically as a way to implement objects, just as, you know, the right thing to do. And we needed lambda (rings) in the first place for the sake of higher order functions.

So I guess your "list ..." column represents 2.0. I'm not sure what "list tail" means. Do you mean a list of environment frames (name-value bindings)?

hm. to me it reads as "before, rings would have a dictionary list as an available variable if you indexed them from a number or not, now it still does, but only if you index it with a non-number". to me "binding the ring to the list as environment" means adding it to the scope when it otherwise wasn't there (at least that's my best guess, it's not how i would describe any action involving a ring and i don't really get it)

list tail is just the tail of a linked list. two lists can share a tail, and changing any values in the tail changes it for both lists. this is a form of inheritance, isn't it?

even without the dictionary items, you can imagine a linked list in reverse. if you index backwards from the end, each item is inherited.

i wonder if it would speed up snap to implement linked lists as inherited js arrays, indexing like array[array.length() - index]. i need to find an excuse to use that concept in one of my projects.

Sorry, I explained it badly. If you want to use a function in the second column to mean an object method, it has to have access to the object's fields, i.e. the names in the first column. This is implemented by (automatically) calling the method in an environment that's extended with a frame in which the variable names in the first column are bound to the values in the second column. It's really elegant, but it would mess up a non-OOP-2.0 project with a dictionary whose first column happens to include a word that's also the name of a variable in the current environment.

Oh. I wouldn't have said so. It's a form of sharing, but the two lists that share a tail are peers; the one that created the list isn't the parent of the one that decided to share part of it. But I see what you mean now.

This is a sore point for me. For a long time I insisted to Jens that in some cases using arrays in a recursive algorithm has to take O(n^2) time, because every call to ALL BUT FIRST OF requires copying the tail of the array to a new array. And I still insist on that, in principle. Alas, interpreting Snap! code is sufficiently slow that for almost all list lengths that come up in actual Snap! projects, that order of growth factor is outweighed by the constant factor speed of arrays. (This is especially true because by the time the list is long enough for the order of growth to win, you've run out of browser memory, because linked lists take ≈ twice as much space.)

We do use JS arrays if your algorithm uses the list command blocks, ADD and REPLACE and so on. It's only if you use IN FRONT OF and ALL BUT FIRST OF to write a purely functional recursive function that you get a linked list. Over time Jens has gradually convinced me that, for example, MAP should make an array if given an array as input. (My original implementation of MAP used IN FRONT OF etc.) And yes, if you use both the functions and the commands on the same list, it gets converted back and forth, and your program is extra slow. The manual explains all this, with examples.

in that case, rings also inherit from lists. this means that a ring can inherit from everything in the table, which implies complexity that's a bit terrifying.
if i understand correctly, it means i could do this to add an entire dictionary to the current scope instantly:

no no, the two lists have heads, which are the children, and the tail is the parent. in the code example above, i inherit the dictionary to add the continuation; i don't modify the dictionary itself.

from my experience and reading from people far more experienced than me, linked lists are almost always slower than regular arrays even in fast system code. if you really have complex enough data and the right use case that makes a linked list better, the one in a standard library is never sufficient. i don't think they should come in standard libraries at all. i don't even think they should be called lists, they're paths. a list is something you can jump to the middle of, do binary search, sort, etc. i don't like them.

the ALL BUT FIRST OF and IN FRONT OF blocks seem odd to me, they aren't particularly useful as-is. they would be much more useful if you could put a whole list in front of another list, or index in much further to get a tail.

i much prefer iterators. it moves the "item, next" pattern to control flow instead of storage, and results in excellent functional programming. iterators often don't even need any backing storage! iterator operations have pretty much no runtime cost until you start iterating, and in a compiled language like rust, it's all compile time. you can zip any number of iterators instantly, no list can do that.
just making "numbers from x to y" be an iterator would be incredibly powerful. you could map over it many times and plug that into hyperized blocks and get incredibly fast results. you could get numbers from 1 to Infinity.

snap's rings already make iterators like this possible but i don't think i've seen it done. it wouldn't need any special iterator type, the ring itself is already the iterator.

Man, I'm having such a hard time keeping my fingers still while reading your provocative ... contributions. Must the the punishment the gods have installed for me for making a programming language. It attracts such ... kinds.

Snap! has prototypal inheritance.
1 form.

made a project for iterators. can't save it and share because for some reason i can't log in?
i just get sent back to the home page. i'm still logged into the forums.

i would much rather hear that you're upset than have you slowly build up resentment over time. i honestly thought you had just stopped reading my posts entirely and left it to bh.

can i at least know what it is? is it even the post you're looking at or just my other recent posts?

Remember that "the current scope" isn't a fixed thing. In your example, the entire dictionary is indeed added to the scope of calls to methods in the same list. I'm not sure I'm reading your mind correctly, but it looks as if you think you're declaring the dictionary words as variables in the caller of your RUN block, but that doesn't happen. They're variables only for methods found within the list itself. At least I think so.

So, if you have a list that's a dictionary, let's say with words in column 1 and definitions in column 2, you can confidently look up words without messing up any environments, except in the case in which your dictionary also contains ringed functions in column 2.

I'm not sure how to answer this because I don't know if you've taken an algorithms and data structures course. Do you know what I mean when I say that an algorithm is O(n^2) time?

Sorry, the name for what you want is "arrays." "Lists" generally means linked lists. Scratch taught us to mix up that vocabulary, but the grownups use "arrays" for the random access ones.

They're precisely CDR and CONS, respectively. They are (along with CAR, which is just ITEM 1 OF) the basic building blocks of linked lists. With those as primitive, you can build APPEND, which I guess is the first thing you're asking for. As for indexing much further in, once again, you're asking for arrays, and we have arrays! We just also have linked lists.

This is what the streams library is for! It provides a functional (as in, calling functions and using composition of functions, rather than issuing commands to an iterator) interface to the idea of deferred computation.

Jens, be fair. OOP 2.0 is entirely separate from sprite cloning, even if they're both prototypal. Don't let's quibble about what the word "form" means.

If you're having trouble with this thread, maybe you should yell at me about it; I'm part of it, too, and I'm learning from it.

In The Amateur Magician's Handbook by Henry Hay, he recommends trying out your act in front of a friend and inviting criticism. He says that what your friend says will probably be wildly wrong, but still useful, because you can be sure that something is wrong at the point when your friend complains.

The analogy isn't perfect, because we're not in the business of misleading the audience. But I think it's reasonable to consider that when we're not meeting a user's needs, we don't have to do what the user suggests, but we should consider doing something. So, for example, as I said earlier, I don't think we need to replace the Libraries dialog with one that looks like Scratch, but I do think that with the explosion of libraries, it's now hard to find the one you're looking for. I'm happy to have that issue raised here.

the continuation is placed in front of the list, and then ran. this means that the continuation is in a list with all the variables, so the continuation should have all the variables defined.

i tried to test this but it seems like continuations are just broken. entirely.
untitled script pic
always appears as an empty ring and has no variables.

i know big O notation. it measures how the time of an algorithm increases as it's scaled up. the thing is for linked lists to become efficient you need to reach that very large scale, and when you're at a very large scale, you start having to do a whole lot more than just using a linked list. the types of operations that a linked list excels at also just really aren't that common, and many of the operations that people believe linked lists are good for often have better methods that don't involve linked lists.

snap doesn't actually have a lot of features for linked lists. you can put an item in front, and get every item except the first. that could be done much faster with a regular list stored in reverse, or by storing a variable to use as the start index of a list, or by making a circle buffer. the strongest two use cases i know for linked lists are splitting and cursors, but i don't think snap provides either of those. you'd need to make a linked list manually out of small two-item lists.

i'm not talking about programming there. i'm talking about real lists, like you can write on a paper. have you ever binary searched through a book to find the correct page? to me a list is something that can be browsed.

oh yeah, i forgot about that one! i remember seeing it a while back. it certainly works, but it's not quite as simple as the iterators i'm thinking of. i would just post the project, but i still can't seem to log in.

Did you run that from the scripting area? If so, its continuation is empty. You should write a procedure to test your theory. (For all I know it might be true! Try it. But don't say "continuations are just broken" -- that's the sort of pronouncement that makes Jens angry at you.

What do you think a "regular list" is? And what do you think a linked list is?

Remember that we're a teaching language, and one of the things we want to teach is recursive functions:

and

Yes, there are other ways to do this, some of them faster. But the point is that until you understand this sort of recursive function you can't understand

And yes, there are iterative algorithms for trees also, but they all suck; they're error-prone and impossible to understand. Whereas recursive functions fit trees, which are a recursive data structure, perfectly.

No, actually. I can always make a better position estimate than the midpoint. (If the book is a dictionary, it comes with thumb tabs so I can position directly to the first letter of the word I want. And then, within that first letter, I can use the second letter to make a better guess than halfway through.) Failing that, I use the index, or the table of contents. It's really only computers that do binary searching. And for computers, it's a fine algorithm! This illustrates why I hate metaphors for technical questions.

What you mean is, "I (sarpnt) happen to be familiar with iterators and not familiar with streams." :confused:

i wrote quite a few tests and i couldn't get any of them to work, not even the most basic `run say with continuation`. the variables block is just the point i was sure that whatever it's giving isn't correct.

untitled script pic
it first says an empty ring, then typeerrors on the variables. i don't think there's any simpler test i could do.

sorry, that wasn't clear at all. it's not about how familiar i am with them, when i say iterators are simpler i mean they have less parts, and require less code to work with. from my understanding, a stream holds its first item in the list, while the rust style iterators i'm using are just a ring that returns the next item. all the code that manages streams has to handle the first item of every stream separately from the rest of the stream

i'm not saying streams are worse or that they're harder to use, but they have more stuff going on in them, they're not as simple. some linked lists can be simpler than vecs (resizable arrays), but i certainly get a lot more use out of vecs in my code.

Way back when I was given my first court room assignments my district attorney told me that young lawyers react to being overwhelmed by this new situation in roughly two ways, either by overcompensating their uncertainty with loud cockiness, or by quietly observing the process. He gently advised us to adopt the second pattern.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.