I wish you could do this:
call (this script []) with inputs (list (a) (b) <>) (the script [say (Hi!)])
It would let you create your own constructors for closures, which would allow you to create things which traced call stacks, etc.
Offline
nXIII wrote:
I wish you could do this:
call (this script []) with inputs (list (a) (b) <>) (the script [say (Hi!)])
Maybe I'm misunderstanding, but won't
CALL [CALL [THIS SCRIPT []] WITH INPUTS [LIST (A) (B) < >] WITH INPUTS [THE SCRIPT [SAY <Hi!>]
do what you want?
Offline
bharvey wrote:
nXIII wrote:
I wish you could do this:
call (this script []) with inputs (list (a) (b) <>) (the script [say (Hi!)])Maybe I'm misunderstanding, but won't
CALL [CALL [THIS SCRIPT []] WITH INPUTS [LIST (A) (B) < >] WITH INPUTS [THE SCRIPT [SAY <Hi!>]
do what you want?
I want it to create a closure with the arguments a, b, etc. and body [Say <Hi>].
(Sorry for the typo, I meant "the (the script) block", not "this script")
Last edited by nXIII (2011-02-16 19:01:37)
Offline
Hi nXIII,
so you're getting familiar with Morphic, that's great!
nXIII wrote:
I have to ask...:
Code:
var Morph; //... Morph.prototype = new Node(); Morph.prototype.constructor = Morph; Morph.uber = Node.prototype; //... function Morph() { this.init(); }Why not use either an anonymous function when you declare the variable:
Code:
var Morph = function(){this.init()}; Morph.prototype = new Node(); //...or assign to the prototype after declaring the function and not use a var statement at all?
Well, it's a matter of personal preference. Like all programmers I like my code to be dense and minimalistic. Obviously you do, too. But I also want others to be able to read, understand and reuse this code. That's why I chose to start each section about a new "kind" of object with subsections containing its referenced constructors and its explicit inheritance information aka "class" definition, and only afterwards declaring its methods, starting with instance creation and initialization. I'm hoping that this template will help readers to easily and quickly get the basic idea of what a particular class is about.
I'm also trying to use this same structure with every other class. Some classes, e.g. TriggerMorph or ListMorph, have constructors and initialization methods which are a lot more complex than Morph's. In these cases I feel that they're better understood by first declaring their position in the class hierarchy before getting into the gory details of how they're instantiated and their instances initialized.
It's sort of the same with temporary variables. Most times you don't actually need them, because you might as well nest functions, but they certainly improve the readability of your code, often eliminating the need for comments.
Speaking of vars: You don't need to declare a var named Morph. But I like to keep track where which class get introduced and referenced, and JSLint likes it, too.
What do you think?
Last edited by Jens (2011-02-16 19:50:49)
Offline
Jens wrote:
Well, it's a matter of personal preference. Like all programmers I like my code to be dense and minimalistic. Obviously you do, too. But I also want others to be able to read, understand and reuse this code. That's why I chose to start each section about a new "kind" of object with subsections containing its referenced constructors and its explicit inheritance information aka "class" definition, and only afterwards declaring its methods, starting with instance creation and initialization. I'm hoping that this template will help readers to easily and quickly get the basic idea of what a particular class is about.
I'm also trying to use this same structure with every other class. Some classes, e.g. TriggerMorph or ListMorph, have constructors and initialization methods which are a lot more complex than Morph's. In these cases I feel that they're better understood by first declaring their position in the class hierarchy before getting into the gory details of how they're instantiated and their instances initialized.
What do you think?
Maybe it would be better to use a class definition function, something like this:
var Node; var Morph; //... Morph = Class({ construct: function() { this.init(); }, uber: Node, properties: { toString: function(){...} } });
That way you can retain the grouped var statements but also use a clean, easy-to-read (I'm not saying we should use that exact syntax, it was an example) method for creating classes, which can also be used to implement class features specific to Morphic.js
EDIT: or simply:
var Node, Morph; //... Morph = Class({ construct: function(){...}, uber: Node, toString: function () { return 'a ' + (this.constructor.name || this.constructor.toString().split(' ')[1].split('(')[0]) + ' ' + this.children.length.toString() + ' ' + this.bounds; }, //... });
Last edited by nXIII (2011-02-16 19:54:01)
Offline
nXIII wrote:
I want it to create a closure with the arguments a, b, etc. and body [Say <Hi>].
(Sorry for the typo, I meant "the (the script) block", not "this script")
Ah, now I get it. The hard part is that your notation doesn't give you orange ovals for the formal parameters.
I agree, that'd be nice. You and about five other people would use it, of course. I'm trying to figure out how we could fit it into the notation we have. Maybe if you made a block with a multiple-input parameter and an upvar, and assigned the former to the latter, and then users of your block could use the upvar to get at the actual arguments?
Offline
nXIII wrote:
EDIT: or simply:
Code:
nested stuff with curly braces
I'm sorry, but I don't see how this would be any more expressive or more human-readable than the code you question.
Last edited by Jens (2011-02-16 20:59:21)
Offline
bharvey wrote:
Ah, now I get it. The hard part is that your notation doesn't give you orange ovals for the formal parameters.
I agree, that'd be nice. You and about five other people would use it, of course. I'm trying to figure out how we could fit it into the notation we have. Maybe if you made a block with a multiple-input parameter and an upvar, and assigned the former to the latter, and then users of your block could use the upvar to get at the actual arguments?
I was thinking maybe a multi-upvar slot would work by providing the block code with a list (which had a constant size) of the values of each upvar. The only other significant problem would be variable numbers of arguments, which could be implemented by adding an "inputs" upvar to the end of the closure block. That way, a "closure" block would look something like this:
CLOSURE {^args...} {body [ }
REPORT [THE SCRIPT. {inputs} [
{#} FOR EACH {input} in {inputs} [
REPLACE ITEM (#) of (inputs) with (input)
]
REPORT [CALL (body)];
]]
@Jens:
Instead of writing:
var Morph; // Morph inherits from Node: Morph.prototype = new Node(); Morph.prototype.constructor = Morph; Morph.uber = Node.prototype;
You would write:
var Morph; Morph = Class({ uber: Node });
The Class function handles prototypes, inheritance, etc., allowing the developer to focus on the class itself and not JavaScript syntax for creating the class and its methods. It also allows things like
construct: function() { this.sup(arguments); }
(i.e. to call overridden method of superclass) which would usually take unnecessary amounts of code.
Offline
Hi nXIII,
good point and interesting discussion!
I kinda like the JavaScript syntax because it directly accesses prototypes instead of adding additional layers of classification and universalization. Plus, I like JavaScript's prototype mechanism, as it is pretty much exactly what we're trying to go for in BYOB 3.1.
You're certainly right that additional layers of abstraction might reduce a few lines of code elsewhere (btw did you actually count the lines of code? Mine: 4, yours: 7, plus you first need to define "Class" ), and your example of "super" is a good one. However, much as I like abstraction I find it challenging to maintain a reasonable balance between abstraction and expressiveness. IMO there's a certain point where further abstraction obfuscates a statement rather than disambiguify it. But this is a tricky issue, and I'm sure many mathematicians and logicians will disagree with me and lean more towards your point of view.
This balance between directness and abstraction is actually something I greatly admire John Maloney's Scratch Source Code for. In my previous programming work I tended to abstract anything and everything, breaking down each method into its subparts and factoring out generalizations. This is all well and good, and apparently one of the proven concepts of state-of-the-art programming. But it also leads to meta code that's very hard to get one's head around in, especially if you're more or less alone and the codebase is becoming really big, like BYOB's or even not so big yet as Morphic's.
Since working on Scratch 1.4 and BYOB I've been training myself more towards longer methods with more temporary variables and fewer layers of abstraction. But it's a delicate balance, susceptiple to all kinds of nitpickings from the pros.
Last edited by Jens (2011-02-17 12:47:07)
Offline
Jens wrote:
I kinda like the JavaScript syntax because it directly accesses prototypes
So do I
instead of adding additional layers of classification and universalization. Plus, I like JavaScript's prototype mechanism, as it is pretty much exactly what we're trying to go for in BYOB 3.1.
You're certainly right that additional layers of abstraction might reduce a few lines of code elsewhere
Actually, I don't really consider the amount of lines to be a big issue (unless there's a big difference
(btw did you actually count the lines of code? Mine: 4, yours: 7, plus you first need to define "Class" )
Wait, what?
and your example of "super" is a good one
I took it almost directly from the Qooxdoo
syntax (this.base(arguments)).
there's a certain point where further abstraction obfuscates a statement rather than disambiguify it.
I don't think that my suggestion goes that far. I think it helps keep a separation between class definitions themselves and the JavaScript which actually creates those classes and provides a pleasant interface for using them.
PS: Why do we use nop()? It seems like, since it does nothing, it simply shouldn't be there, or we should use it instead of function(){}.
Offline
nXIII wrote:
PS: Why do we use nop()? It seems like, since it does nothing, it simply shouldn't be there, or we should use it instead of function(){}.
nop() does explicitly nothing, and 'nop' is used as its selector in places that expect a selector, such as menu items.
At first selectors was the only thing I provided for in menu items (because it's the only thing allowed in Smalltalk menus), only at a later stage in development did I extend menus and buttons to also accept anonymous functions as well as selectors. I'm still torn between those two. On one hand I love lambdas, and using functions instead of selectors feels very "direct" and elegant. But it's one of those things that really clutter up code with ugly nested structures. Selectors, OTOH require more discipline, but the code is much 'flatter', plus, selectors (strings indicating named functions) are late-bound.
Last edited by Jens (2011-02-17 15:52:20)
Offline
Jens wrote:
nXIII wrote:
PS: Why do we use nop()? It seems like, since it does nothing, it simply shouldn't be there, or we should use it instead of function(){}.
nop() does explicitly nothing, and 'nop' is used as its selector in places that expect a selector, such as menu items.
At first selectors was the only thing I provided for in menu items (because it's the only thing allowed in Smalltalk menus), only at a later stage in development did I extend menus and buttons to also accept anonymous functions as well as selectors. I'm still torn between those two. On one hand I love lambdas, and using functions instead of selectors feels very "direct" and elegant. But it's one of those things that really clutter up code with ugly nested structures. Selectors, OTOH require more discipline, but the code is much 'flatter', plus, selectors (strings indicating named functions) are late-bound.
No, I meant in cases like this:
Morph.prototype.step = function () { nop(); }; //vs. Morph.prototype.step = function(){};
Offline
I finally got around to learning Python! So far, it has been pretty easy. Its interesting to see how I can apply what I've learned in BYOB to Python. Though in my opinion, its far easier to make sense of first-class data with BYOB's visual representation than in text-based languages. BYOB does a great job (thanks to Brian and Jen's hard work) of representing each block with an appropriate shape and corresponding input slot. Its a lot easier to make sense of what's going on in BYOB than with the pure text you get in other programming languages. Great job!
JavaScript will come soon.
Offline
shadow_7283 wrote:
it's far easier to make sense of first-class data with BYOB's visual representation than in text-based languages.
Thanks! That neatly sums up what we've been trying to achieve -- and the argument I have to make all the time to people who think higher order functions are too difficult for high school kids.
If you go from BYOB to Python to Javascript, you're going to end up thinking that every language has lambda.
Offline
You should be able to create blocks that are available to any project you make, ones you don't have to remake and import a sprite with the blocks. It would make life easier on making blocks for multiple projects.
Offline
ihaveamac wrote:
You should be able to create blocks that are available to any project you make, ones you don't have to remake and import a sprite with the blocks.
I guess, but what's so hard about exporting a sprite? The trouble with exporting individual blocks is that they tend to come in groups; you write a library to handle, I don't know, converting Roman to Arabic numerals -- and back again. Someone who wants one of those blocks probably wants the other one, too.
And you can delete the sprite once you've used it to import the blocks.
Offline
ihaveamac wrote:
You should be able to create blocks that are available to any project you make, ones you don't have to remake and import a sprite with the blocks. It would make life easier on making blocks for multiple projects.
No, not really... It would our lives alot easier but would not necessarily make Jens life easier... and also it would just be one more non foundational feature to work on Instead of progress in the OOP stuff which hes been working so hard on lately. If you really want to make persistent blocks just save them to the default sprite. (Ask Brian how to do that I 4got exactly what thats called... (tired))
Last edited by 14God (2011-02-19 03:20:16)
Offline
bharvey wrote:
ihaveamac wrote:
You should be able to create blocks that are available to any project you make, ones you don't have to remake and import a sprite with the blocks.
I guess, but what's so hard about exporting a sprite? The trouble with exporting individual blocks is that they tend to come in groups; you write a library to handle, I don't know, converting Roman to Arabic numerals -- and back again. Someone who wants one of those blocks probably wants the other one, too.
And you can delete the sprite once you've used it to import the blocks.
My issue with this strategy is that you often get the blocks you don't want; for instance I would love to be able to open the "tools" sprite and grab the for(init;cond;inc) block without getting everything I don't need.
Offline
Maybe once the block library is created, there will be an 'import from block library' option that can import a block from the block library.
Offline
fullmoon wrote:
I would love to be able to open the "tools" sprite and grab the for(init;cond;inc) block without getting everything I don't need.
Just for you, there is an "Unload unused blocks" item in the Edit menu! (IIRC it doesn't work 100% yet, but we're getting there.)
I know, you want to make the choice on the way in, not on the way out. What you want is an "Import from library" option that would give you a palette with checkboxes next to each block, and then when you click OK it would load just those blocks. But as 14God says, that would be a big effort that right now is better spent on OOP issues.
Tell you what: When we start on 4.0 in April, you can write the Javascript code to implement the checkbox thingy!
Offline
fullmoon wrote:
bharvey wrote:
ihaveamac wrote:
You should be able to create blocks that are available to any project you make, ones you don't have to remake and import a sprite with the blocks.
And you can delete the sprite once you've used it to import the blocks.
My issue with this strategy is that you often get the blocks you don't want; for instance I would love to be able to open the "tools" sprite and grab the for(init;cond;inc) block without getting everything I don't need.
You can try this : create a new sprite, copy the Foreach instruction into it; export the sprite. For me this solution works ...and is very useful.
The issue with export is that you can't export sprites with functions which are still used somewhere else.
Offline
My way to export re-usable library blocks :
1 - I use a "dedicated library" sprite where I define local "varfuncs" rather than named blocks (*) : SET varfunc1 TO C-SHAPE THE SCRIPT +script
2 - This varfunc can be called ( run or launched ) by any other sprite calling this library bvarfunc by : RUN [[varfunc1 OF library ] OF myself]
3 - Any function relative to any sprite (except the Hat controls) can be stored in " library" , acting like a function repository.
4 - To export an updated "library" , rename your project to "library..." delete all other sprites except the sprite library, save the project to library0219 for example.
5 - At any moment (for a new project or a current one) you can IMPORT this project and you get back all your scripts.
6 - You can also save usual costumes as costumes of the "sprite library" as to get them immediately available to test the loaded varfuncs.
7- After Importing the "library" project your need to reset the varfuncs, which takes few seconds.
(*) the method works probably alike with named functions.
Offline