An OOP paradigm mixing Class and Prototype

20 views
Skip to first unread message

Jingcheng Zhang

unread,
Mar 1, 2010, 3:01:37 AM3/1/10
to FalconPL
Hello everyone,

After reading the OOP section of falcon survival guide, especially the
"hacking-like"
prototype model in falcon, I raised some thoughts, which, personally,
looks more
consistent in language syntax level. I would like to post it here, to
request for
comments :-)

First, I'd like to refer a paper on this topic:

http://web.media.mit.edu/~lieber/Lieberary/OOP/Delegation/Delegation.html

And the basic concepts:

http://en.wikipedia.org/wiki/Class-based_programming
http://en.wikipedia.org/wiki/Prototype-based_programming

And here are the thoughts:

* The paradigm should support both Class-based OOP and Prototype-
based OOP;

* Basic elements in this paradigm are: <object>, <class>,
<instance>;

* <object> is the basic element, an <object> consists of
properties and methods;

* <object> implements the "prototype" concept in Prototype-based
OOP;

* <object> is standalone and unique, and is not an <instance> of
any <class>;

* Example syntax of an <object> definition:

object falcon
creator = 'Giancarlo Niccolai'
version = '0.9.6.2'
paradigms = ['procedure', 'object-oriented', 'functional',
'message', 'tabular']
function introduce()
> 'Falcon is created by ' + self.creator + ', current
version is ' + self.version
end
end

* <object> can derive from another <object>, for example:

object python
// properties and methods for python
end

object lua
// properties and methods for lua
end

object falcon from python, lua
// properties and methods for falcon
end

Here, falcon inherits properties and methods from both python
and lua.

Inside the syntax, falcon maintains a prototype-chain, which
support accessing
missing properties and methods following the chain. This is
called "delegating";

* <class> is a special <object>, it can be instanciated to create
many <instance>s;

* <class> abstracts common properties and methods of a group of
<instance>s;

* <instance> is NOT <object>, and <object> is NOT <instance>
either;

* Example syntax of a <class> definition:

class committer(name)
// class property
static project = 'falcon'
// instance member
name = nil
init
this.name = name
end
// class method
static function get_project()
return self.project
end
// instance method
function say()
> 'I am ' + this.name + ', a committer of ' +
self.get_project() . ' project'
end
end

jonnymind = committer('Giancarlo Niccolai')
jonnymind.say()

* <class> can derive from another <class>, for example:

class web_committer(name, category) from committer(name)
// class property
static svn_repository = 'svn://falcon.org/...'
// instance property
category = category
// instance method
function say()
super.say()
> 'And I work in ' + this.category . ' sub-project'
end
end

diogin = web_committer('Jingcheng Zhang', 'nest')
diogin.say()

Of course, <class> can inherits from multiple <class>es just
like <object>;

* So, properties in <object> are equivalent as static properties
in <class>,
and methods in <object> are equivalent to static methods in
<class>, they
all follow the rules of delegation to access the prototype-
chain;

* <object> members or static members of <class> are referred with
"self.",
and <instance> members are referred with "this.", which helps
developer
differentiate the member-level easily.

Giancarlo Niccolai

unread,
Mar 1, 2010, 4:37:30 AM3/1/10
to falc...@googlegroups.com
Jingcheng Zhang wrote:
> Hello everyone,
>
> After reading the OOP section of falcon survival guide, especially the
> "hacking-like"
> prototype model in falcon, I raised some thoughts, which, personally,
> looks more
> consistent in language syntax level. I would like to post it here, to
> request for
> comments :-)
>

Your ideas have some interesting points, which I'd like to keep into
consideration; read below.

However, let me warn the audience about one very practical
consideration. In my short and limited experience as a language
designer, I have noticed that special syntax addressing a special
problem is not always helpful as it may seem at first glance.

For example, LISP, one of the most powerful languages of all times, has
nearly zero special syntax constructs, and a very simple set of basic
syntax elements.

Conversely, languages having special syntax for everything tend to be
rather "rigid". Often, problems resolved with special syntax constructs
have been better profiled and resolved through a "function library"
approach. Consider rules and constraint programming as solved by Prolog
and as solved by C, Java and Python libraries. Despite the fact that the
former was specifically meant to address that particular class of
problems, the same problems expressed through "rules" object sets are
even more readable and compact.

A still valid reason to provide special constructs may be assistance of
the compiler in optimizing during compile time. However, modern
approaches to compilation process has lessened this need; consider, just
for instance, the special Python function "min(a,b)", which is resolved
at compile time into VM opcodes and doesn't generate a real call to a
function called "min".

Considering all this, the "hacking" approach to prototype OOP doesn't
seem so "hacking" at all. Conversely, caging prototype OOP into a
language-defined set of structures may deprive the final users of some
potential that make POOP so interesting. In Falcon, Prototype OOP can be
"programmed" from the inside and the outside, with the ability to
dynamically change the structure of prototype "objects", (let's call
them b-dict, blessed dictionaries, to avoid confusion with "instances"),
without the need of special grammar to address this problem. Forcing a
grammar into the current model would inevitably give off some of the
potential of this paradigm, trading it off with a "clarity" which may be
more a matter of personal taste than of an objective advantage.

Also, "grammarizing" the approach to prototype OOP seems to go against
the modern 5th generation languages tendency which goes on the other
direction. Consider the case of Lua, which is totally prototype OOP
oriented and proudly refuses to introduce any grammar construct to deal
with prototype OOP. Their tables, not unlike our dictionaries, are a
perfect abstraction of the media that should carry POOP values; or in
other words, if you had to write a POOP support, you'd need to write a
structure similar or identical to Lua tables to drive your POOP system.
So, Lua ppl said: "Hey, we got the tables to make POOP; what about
giving THEM to the users, so THEY do POOP instead of us doing it for them?"

As you can see, this approach has the disadvantage of taking some of the
control a grammar framework can grant away from the compiler; but it has
two relevant advantages of 1) making the compiler and the underlying
language support simpler (and so, more efficient) and 2) making it more
powerful and extensible.

We're in the same situation of Lua ppl, with some minor difference in
the structure of our dictionaries with respect to their table;
differences that do not affect the way POOP can be built.

Now, and here I follow your ideas, what we can do to make our POOP
support stronger is twicefold:
1) providing some poop oriented method or function for dictionaries. For
example, create a sort of inheritance declaration via

Dictionary.inherit( d1, d2 .... dn )

Even without special grammar, we may be able to perform some type
inference (when we introduce type contracts) and be able to even solve
part of this inheritances at compile time.

2) Providing language bound POOP "class" system (either in core or as a
separate module). For a reference, search for the various Lua class
libraries, which expose an "ordinary" POOP entity they call "class",
with its own inheritance schemes, and the ability to create "instances"
via a call to one of their member. Creation of an instance (entity)
includes the addition of the "base class" automatically as one of its
members.

However, whatever we do we cannot call "object" a POOP entity, mostly
for historical reasons (because of the special meaning of the keyword
"object" in Falcon), but we can use another term to name them. For
example, we may go for "entity", or if you want to sound more
"scientific", "p-entity".

About forking "self" and "this" I can't see any practical advantage, as
the context of self or this is always the same: "the thing I am
currently in". You'd just bring the same confusion you have in C (not
C++) when you can access structures by "." or "->". The only interesting
thing of having them different is that the compiler will slap you if you
mistake one for the other, and you'll have to go back and put in the
right one. And then, the semantic difference between "." and "->" is
even greater than the semantic difference between "this" object being an
"instance", a "p-entity" or an "object".

However, you know I am open to change my mind if proven wrong; we did it
several times since the beginning and we'll do it again for sure. So, if
you feel my arguments are weak, don't be afraid to bash them :-)

Bests,
Giancarlo.


Jingcheng Zhang

unread,
Mar 1, 2010, 10:54:20 PM3/1/10
to falc...@googlegroups.com
Giancarlo,

Thanks for your detailed description on this topic. My ideas are:

2010/3/1 Giancarlo Niccolai <g...@niccolai.cc>


Your ideas have some interesting points, which I'd like to keep into consideration; read below.

However, let me warn the audience about one very practical consideration. In my short and limited experience as a language designer, I have noticed that special syntax addressing a special problem is not always helpful as it may seem at first glance.

For example, LISP, one of the most powerful languages of all times, has nearly zero special syntax constructs, and a very simple set of basic syntax elements.

Conversely, languages having special syntax for everything tend to be rather "rigid". Often, problems resolved with special syntax constructs have been better profiled and resolved through a "function library" approach. Consider rules and constraint programming as solved by Prolog and as solved by C, Java and Python libraries. Despite the fact that the former was specifically meant to address that particular class of problems, the same problems expressed through "rules" object sets are even more readable and compact.

A still valid reason to provide special constructs may be assistance of the compiler in optimizing during compile time. However, modern approaches to compilation process has lessened this need; consider, just for instance, the special Python function "min(a,b)", which is resolved at compile time into VM opcodes and doesn't generate a real call to a function called "min".

Considering all this, the "hacking" approach to prototype OOP doesn't seem so "hacking" at all. Conversely, caging prototype OOP into a language-defined set of structures may deprive the final users of some potential that make POOP so interesting. In Falcon, Prototype OOP can be "programmed" from the inside and the outside, with the ability to dynamically change the structure of prototype "objects", (let's call them b-dict, blessed dictionaries, to avoid confusion with "instances"), without the need of special grammar to address this problem. Forcing a grammar into the current model would inevitably give off some of the potential of this paradigm, trading it off with a "clarity" which may be more a matter of personal taste than of an objective advantage.

Also, "grammarizing" the approach to prototype OOP seems to go against the modern 5th generation languages tendency which goes on the other direction. Consider the case of Lua, which is totally prototype OOP oriented and proudly refuses to introduce any grammar construct to deal with prototype OOP. Their tables, not unlike our dictionaries, are a perfect abstraction of the  media that should carry POOP values; or in other words, if you had to write a POOP support, you'd need to write a structure similar or identical to Lua tables to drive your POOP system. So, Lua ppl said: "Hey, we got the tables to make POOP; what about giving THEM to the users, so THEY do POOP instead of us doing it for them?"

As you can see, this approach has the disadvantage of taking some of the control a grammar framework can grant away from the compiler; but it has two relevant advantages of 1) making the compiler and the underlying language support simpler (and so, more efficient) and 2) making it more powerful and extensible.

We're in the same situation of Lua ppl, with some minor difference in the structure of our dictionaries with respect to their table; differences that do not affect the way POOP can be built.


I agree totally with you on the language power distinction between builtin grammar support and support through library. But I have some different points too.

1. Falcon has borrowed a lot of features from other languages, like class syntax from Java/C++, indirect variable accessing from PHP, etc. These features, although not completely, can largely be implemented through libraries too. But Falcon provides most of them, why? Because it simplified the expression, it makes a programming language more expressive, it helps you write your thoughts convienently.  As you indicates, Falcon focus more on the ability of expression, compared to readability of the code. If Falcon can be more expressive by providing a grammar support of POOP, why can't we do it? This, compared to "blessing a dictionary to get a prototype entity", makes Falcon more consistent in language level.

2. Low level construction makes the language powerful compared to "rigid" language syntax, true. But from the marketing view, "rigid" language syntax helps the adoption of the language. Lisp, and lua, are known to be powerful. But they are a failure in the language market, since they are not friendly to programmers. On the other hand, Java, PHP, Visual Basic, all have a "rigid" language syntax, so people can learn the language quickly and use them widely, which in turn improves their market adoption.

3. A rule of 80/20 is known to us. Basically, we can provide 80% ability of POOP support through language syntax, while the left 20% is provided through library or low level language constructs. In fact, POOP paradigm is so natural and simple that I even can't see any need to use library..

4. The "bless" function is not meaningful. If I tell a developer: "You can bless a dictionary to get a prototype entity", can she understand the meaning of "bless" quickly? I searched "bless" in English dictionary, and I can't find a meaning other than the meaing in "God bless you". Personally, I prefer precise and meaningful word, let alone this is a core programming paradigm support of Falcon.
 
Now, and here I follow your ideas, what we can do to make our POOP support stronger is twicefold:
1) providing some poop oriented method or function for dictionaries. For example, create a sort of inheritance declaration via

 Dictionary.inherit( d1, d2 .... dn )

Even without special grammar, we may be able to perform some type inference (when we introduce type contracts) and be able to even solve part of this inheritances at compile time.

2) Providing language bound POOP "class" system (either in core or as a separate module). For a reference, search for the various Lua class libraries, which expose an "ordinary" POOP entity they call "class", with its own inheritance schemes, and the ability to create "instances" via a call to one of their member. Creation of an instance (entity) includes the addition of the "base class" automatically as one of its members.

However, whatever we do we cannot call "object" a POOP entity, mostly for historical reasons (because of the special meaning of the keyword "object" in Falcon), but we can use another term to name them. For example, we may go for "entity", or if you want to sound more "scientific", "p-entity".


I prefer the second solution, and the "entity" keyword :-)
 
About forking "self" and "this" I can't see any practical advantage, as the context of self or this is always the same: "the thing I am currently in". You'd just bring the same confusion you have in C (not C++) when you can access structures by "." or "->". The only interesting thing of having them different is that the compiler will slap you if you mistake one for  the other, and you'll have to go back and put in the right one. And then, the semantic difference between "." and "->" is even greater than the semantic difference between "this" object being an "instance", a "p-entity" or an "object".


It may be more clear to inform the source reader/writer which level (entity/class/instance) they are at. Personally, I think it's a bad idea to mix them all with "self". And I loves the distinction of "." and "->" in C, too :-)
 
However, you know I am open to change my mind if proven wrong; we did it several times since the beginning and we'll do it again for sure. So, if you feel my arguments are weak, don't be afraid to bash them :-)


My ideas come from the process of designing my web framework. The HTTP driven web programming is more comfortable to use the POOP model, so I would like to see straightforward POOP support in Falcon. Since I have only limited programming experience, so the ideas are just only a reference to Falcon :-)
 
Bests,
Giancarlo.



--
You received this message because you are subscribed to the Google Groups "FalconPL" group.
To post to this group, send email to falc...@googlegroups.com.
To unsubscribe from this group, send email to falconpl+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/falconpl?hl=en.




--
Best regards,
Jingcheng Zhang
P.R.China

Paul Davey

unread,
Mar 2, 2010, 1:17:09 AM3/2/10
to falc...@googlegroups.com
I strongly disagree with changing the language syntax, however if delegation is something that is desired i suggest providing some standard methods that may be placed in certain slots to perform the delegation and registering of prototypes

bless is most probably a historical thing from perl 5, to bless is to bestow something good upon, so it pretty much just makes it a special dict

Giancarlo Niccolai

unread,
Mar 2, 2010, 4:10:10 AM3/2/10
to falc...@googlegroups.com
Paul Davey wrote:
> I strongly disagree with changing the language syntax, however if
> delegation is something that is desired i suggest providing some
> standard methods that may be placed in certain slots to perform the
> delegation and registering of prototypes
>
> bless is most probably a historical thing from perl 5, to bless is to
> bestow something good upon, so it pretty much just makes it a special dict
The reason of blessing dictionaries is very practical. As any language
entity, dictionaries have methods (for example, .len()). Susppose that
all dictionaries may be oop accessed, like i.e. in Lua. Then every "."
access would scan the whole dictionaries, even when the user doesn't
absolutely want it to be a POOP instance, and has no interest in
searching the properties in the whole dictionary. For example, think of
creating a dict of 10000 elements and then doing .len() ....

Gian.

Giancarlo Niccolai

unread,
Mar 2, 2010, 4:31:17 AM3/2/10
to falc...@googlegroups.com
Paul Davey wrote:
> I strongly disagree with changing the language syntax, however if
> delegation is something that is desired i suggest providing some
> standard methods that may be placed in certain slots to perform the
> delegation and registering of prototypes
>
> bless is most probably a historical thing from perl 5, to bless is to
> bestow something good upon, so it pretty much just makes it a special dict
... and I buy the idea of some more formal delegation and prototype
registering operators/keyword/methods.

I am open to suggestions

GN.

Paul Davey

unread,
Mar 2, 2010, 7:05:04 AM3/2/10
to falc...@googlegroups.com
I suggest providing an implementation of a delegated getProp and setProp methods for blessed dicts that may be dropped into the appropriate slots in an existing dict to get delegation behavior, the setProp is less needed as i think it would simply be a search for a prop name in the prototypes and then have that slot be created in the existing dict and set

I thing using __protos for the protos list would not be a bad idea and have this be an Array or List of blessed dicts where methods will be looked up and invoked on the current dict

Earl Montgomery

unread,
Apr 14, 2018, 8:38:08 AM4/14/18
to FalconPL
When I saw the term "blessed" dictionary and the term POOP I giggled but it felt exciting.  Using plain terms puts you to sleep.  I fell in love with Python because of the excitement of the language and I am falling in love with Falcon for that same reason.  I see the points on both sides of the coin here and JingCheng Zhang has some compelling arguments but I just wanted to add what has sparked and maintained my interested inf Falcon.
Reply all
Reply to author
Forward
0 new messages