Really nice language, with similarities to SmalltalkLanguage, but PrototypeBased, and things from LispLanguage and JavaScript.
Still in beta, but pretty functional, it's being developed by ManuelTomis. I am just helping for testing, examples, &c...
See http://brain.sourceforge.net/ for more. I am sure you'll like it :) -- DavidDeLis
Don't you mean 'similarities to SelfLanguage'? The syntax seems a little kooky - what was wrong with Self's syntax? -- RichardEmerson
I agree -- the syntax is kooky. I'd like to learn more about the reasons for developing this language. Having spent two years working in a prototypical language (now dead), I'm always eager to learn about others. I'm assuming there are some shortcomings in SelfLanguage that BrainLanguage is focusing on overcoming. What are they?
On a brief scan of the docs, I saw one point that really troubles me: "If the method or property is found in the prototype then it is the prototype that becomes the receiver object of the message." If the prototype is the receiver, how do you override data members? I'm accustomed to the original object remaining the receiver so that further member lookups begin there. -- GregVaughn
What does kooky mean? As far as I know from email interchange with the author (a young CSC student in Chyprus) he looked some books of Smalltalk and JavaScript and liked it, so he started to make the BrainLanguage. I didn't know Self, although I did know a bit about Newtonscript. I'll point ManuelTomis to this wiki and to the pages given on the SelfLanguage page and see what he thinks. The language is slowly changing and even today I have some proposals for changes to send to him. It would be nice if people interested would get in touch with ManuelTomis, he will surely appreciate any and all input about BrainLanguage.
As for my own opinion, I like it because it's really clean, without some extra syntax commonly found in Smalltalk that usually remains void, &c.
Regarding prototypes, you don't have to delegate, you can subtype. That means the new object is a clone of the first one but with added functionality or data... (properties)...
This is an example I am making myself for the examples section:
Person = object subtype property: #name is: ""; -- defaults property: #age is: 0; method: #get_name is: { self!name }; method: #get_age is: { self!age }; method: #set_name: is: { |new_name| self!name = new_name }; method: #set_age: is: { |new_age| self!age = new_age };.
And then you can subtype or delegate Boy, Girl, Baby, &c... It's extremely clear, (specially written in this C++/Java look&feel... I am still looking the right style for this language.. any suggestions very appreciated :)
If you have to override data members for an object, you should refactor it to be a subtype of its parent and not delegate that functionality to it. I see delegation like in legal matters. If a young boy does something bad, he is delegating the responsibility to his parents (until he is over 18/21 years-old) and thus the father/mother/legal tutor becomes fully receiver of the message (sent by Justice in this example...) I may be off-the-track, though...
Hope this helps... -- DavidDeLis
Newtonscript was actually the Self derived language I have experience in. I haven't had the chance to read through all the details of the docs, so correct me if I'm wrong about subtyping in BrainLanguage: a subtype of X is an object with X as it's prototype. Suppose you create a Baby class with your example Person as its prototype, and it does not override the getName method, but it does have it own name property. If you sent a getName message to Baby would it return the name from Person or Baby? My reading of the rule that the prototype becomes the receiver would mean that it would return name from Person, which is not what I would want. -- GregVaughn
Actually Babies are down in the chain of my example... :-) That would only happen if Baby delegate its methods to Person. Problem here is how you model the whole thing: a baby IS-A person or a baby IS-LIKE a person? (using Scott Meyers' relationships (we've left HAS-A out))
If a baby IS-A person, then:
Let's suppose:
Animal = object new.-- an animal (instance of object) -- Animal = object subtype. -- this would yield a specialization of object... Person = Animal subtype. -- a person IS-A animal Baby= Person subtype. -- it would have all data and methods from Person.But if Baby = Animal subtype property: #prototype is: #Person.
In this case, we are stating that a Baby is an animal, the same way a Person is, that a Baby is not a Person, but that it behaves in a similar way... (IS-LIKE). I think I remember Coplien or Meyers have a discussion on C++ inheritance: IS-A is public inheritance, HAS-A is private inheritance and IS-LIKE is protected inheritance... or a permutation of the two last ones... I wonder is that right? Hope this makes things clearer... -- DavidDeLis
Sorry, but I still don't see it. I guess I should read the BrainLanguage docs more. It sounds to me from your example that the 'subtype' keyword is not the same as setting a prototype, which was the assumption I made above. Still if
Baby = Animal subtype property: #prototype is: #Person, property: #name is: "Junior"and I call Baby.getName() (or whatever the syntax is) will it return "Junior" or whatever name is defined as in Person? -- GregVaughn
About the question why I wrote BrainLanguage. About 2+ something years ago I decided to write a programming language, just for fun :) I started looking around on the net and i had a good look at languages like JavaLanguage, PythonLanguage, SchemeLanguage, SmalltalkLanguage, SelfLanguage, PikeLanguage, JavaScript, HaskellLanguage and a few more. After trying some approaches I finally decided on the general design of BrainLanguage at the beginning of last year. BrainLanguage is obviously influenced a lot from SmalltalkLanguage/SelfLanguage. Basically I liked the ideas behind those languages but there were also some things I didn't like, so I borrowed the general ideas about the syntax and the semantics, but I decided to do the rest the way I wanted to. So what are the differences between BrainLanguage and SelfLanguage?
First of all there are some obvious syntactic differences ex. identifiers can contain dash, blocks and literals have kind of different (kooky ?:) syntax etc. Local variables in BrainLanguage are introduced with the var keyword. Besides the usual unary/binary/keyword message syntax, BrainLanguage has a block evaluation syntax (). This makes evaluating blocks more convenient rather than using block value: ??? value: ??? value: ???, and allows blocks to be used like functions in other languages. You can access properties of objects with object!property syntax rather that the system creating special methods. There are also semantic differences: BrainLanguage supports SchemeLanguage style closures, and it does not have a non local exit ^ because it would make no sense given the semantics of blocks in BrainLanguage. In BrainLanguage all blocks are equals, that is there is no distinction between methods and blocks. Also BrainLanguage supports single delegation, instead of multiple delegation, because I thought the complexity wasn't worth it. One of the most important differences is that BrainLanguage libraries do not have much in common with the SelfLanguage libraries (although again there are methods that have similar names).
Last but not least SelfLanguage and SmalltalkLanguage usually come with a set of thousands of objects, which live in a persistent image. From what I saw SelfLanguage is worth about 15 megabytes of download. I preferred to make BrainLanguage run more like a traditional scripting language like PerlLanguage or PythonLanguage.
Now about the (kooky :) semantics of BrainLanguage objects. Delegation in BrainLanguage means something like "I don't understand this, will you do it for me?". So why does the prototype become the self object?
The first reason is that each object is supposed to work on it's own data, and is not supposed to know about the data in objects that it is the prototype of. Let's say that an object A has a property called Data. Let's say that this object is the prototype of another object B which also has a property called Data. Let's assume that a message make-it-so is sent to B, is not found, and is then found in A. I think that A's method make-it-so should work on it's own object's Data rather on B's data.
A second reason for having these semantics is that you can have native objects (like strings/chars/numbers) as prototypes. For (a not very useful) example:
object!prototype = "Hello World". object reverse println.A third reason is that you can have different objects share the same prototypes properties (something like virtual inheritance in C++)
And finally about the meaning of subtype. In BrainLanguage there is a concept of types, like for example all strings are considered to be of string type. When you add a method to an object, that method will automatically be added to all objects of the same type. What the subtype message does is that it clones an object and at the same time it makes it to be of a new type. Think of it like creating a new species in the process of evolution :). The object will have all the properties and methods of the original object, but if you add a new method to it, it will be added only to itself and any objects that were cloned from it (that is objects that are the same type with it).
I hope that this information was useful. -- ManuelTomis
Aha! I did read that rule about the prototype becoming the receiver properly. From my experience with NewtonScript, that seems terribly limiting. The fact that I could override data without overriding methods was very helpful. However, if I'm understanding subtypes correctly (I haven't experienced anything like it before), it looks like you can get the same sort of functionality at the memory expense of a clone. That wouldn't have been acceptable in the low-memory environment of the Newton, but it is probably fine on a desktop. The subtype sounds an awful lot like an instance of a class, but I thought this was a prototypical language :-) -- GregVaughn
:-) Well, every object in Brain (as Manuel has told me) has two parts: a data space and a methods space (think of boxes). Every object of a given type shares the methods box, while maintaining a private data box. Cloning a new object of that type simply creates a new data box... It's like if we had this:
[data|methods] == [data| *p],p--> [methods] So ob1 = [data1| *p], ob2 = [data2| *p], etc...On the other hand, if we subtype from an object, the new object had a methods box of its own, and it's effectively separated from it's parent object.
If may be like inheritance in class-driven languages, but if o2 = o1 subtype, you can after this add methods and properties to both objects. They will share a common ground, but their behavior will be pretty different (so that could mean there's a virtual parent object would be there floating around... but there is not :-)
By the way, it's all down to using the appropriate idioms for the language. You can do it class-like by maintaining an immutable object as a template or you can create a dynamic world were objects just evolve as needed. ExtremeProgramming would probably be a good methodology for this, as RefactorMercilessly and DoTheSimplestThingThatCouldPossiblyWork sound pretty much like the above... I don't know many idioms myself (still learning). Manuel has already developed some of them, and I am sure many more are still buried in the language. I hope they'll pop up as the language evolves and our understanding of it grows. -- DavidDeLis