* SOS: Simple Object System @ 2008-09-13 22:42 Maciek Godek 2008-09-14 10:22 ` Neil Jerram ` (2 more replies) 0 siblings, 3 replies; 16+ messages in thread From: Maciek Godek @ 2008-09-13 22:42 UTC (permalink / raw) To: guile-user [-- Attachment #1: Type: text/plain, Size: 2266 bytes --] Hi, Using some hints you gave me, I've implemented a really tiny object system -- and I would like to know your opinion ("why it's still better to use goops" :D) The notation for defining classes is following (using example of a sphere): (define sphere (class '(x y radius) '((move (dx dy) (set! x (+ x dx)) (set! y (+ y dy))) (scale (factor) (set! radius (* factor radius)))))) To make an instance, you simply use instance-of: (let ((S (instance-of sphere))) ... ) you can supply initial values to the object's props and call it's methods (let ((S (instance-of sphere 1 2 3))) (in S '(move 1 1)) ;move the sphere from (1 2) to (2 3) (in S '(scale 5)) (get S 'radius)) ; returns 15 The implementation is very simple: every object is a vector. Its first field is always a reference to the class, and the remaining fields are object's state (in the example, the values of x, y and radius of S) A class definition is a vector consisting of: hashmap N from property names to vector indices (in object) hashmap M from member function names to their indices in F vector F of member functions There's nothing surprising in here, and won't be. It has, as I can tell, a few advantages over goops -- mainly, storing objects as vectors allows for an efficient and convenient object treating from C level, so boatmen should be satisfied. Secondly, people accustomed to the object.method() notation (like myself) won't feel lost and the global namespace will be kept clean. The system certainly isn't as complex as goops and doesn't handle types (in general) so exquisitely. Also, it's unable to support multiple inheritance efficiently (single inheritance isn't supported as well, but this could be done quite easily if needed), but that's not my point. I just wanted to ask if you have any comments or remarks to share with (I know I'm not the first guy to implement a thing like this). I am currently using this system to implement another system (for networked objects -- I wrote about it in another post) and so far it caused no trouble. I attach the working implementation (if anyone's interested). For those who got this far (yes, that would be... you!), thanks for your attention :D M. [-- Attachment #2: sos.scm --] [-- Type: application/octet-stream, Size: 3845 bytes --] (use-modules (srfi srfi-1)) (use-modules (srfi srfi-17)) (use-syntax (ice-9 syncase)) (define-syntax let-alias (syntax-rules () ((_ ((id alias) ...) body ...) (let-syntax ((helper (syntax-rules () ((_ id ...) (begin body ...))))) (helper alias ...))))) ;; the `class' function creates a new class. `private' and `public' are lists ;; of symbols (variable names), and `member-functions' is a list of member function ;; definitions of a shape: (name (args) body). (define (class member-vars member-functions) (let ((definition (make-vector 3)) (properties (append '(class) member-vars)) ;; symbols->hashed-indices transforms a list of symbols into a hash table ;; containing integers ranging from 0 to length(symbols)-1, for instance, ;; (symbols->hashed-indices '(a b c)) returns a hash map such that ;; for key 'a' the value is 0, for 'b' 1, for 'c' 2 in other words it ;; returns a hash map X such that for every symbol ;; (eq? (list-ref symbols (hash-ref X symbol)) symbol (symbols->hashed-indices (lambda(symbols) (let ((h (make-hash-table (length symbols))) (count (let((c -1))(lambda()(set! c (+ c 1))c)))) (map (lambda(symbol)(hash-set! h symbol (count))) symbols) h)))) (let-alias ((state-indices (vector-ref definition 0)) (method-indices (vector-ref definition 1)) (methods (vector-ref definition 2))) ; set the names of state variables into a hash table (set! state-indices (symbols->hashed-indices properties)) ; set the names of member functions into a hash table (set! method-indices (symbols->hashed-indices (map car member-functions))) (let* ((build-context (lambda(property)(list property (list 'vector-ref 'self (hash-ref state-indices property))))) (context (map build-context properties)) ;; method->lambda transforms member function definitions into appropreate lambdas. It builds ;; a lexical closure that aliases all properties of a given class as references to a vector "self". ;; for instance, member function 'a=b+n' in the following class definition: ;; (class '() '(a b) '((a=b+n (n) (set! a (+ b n))))) ;; will be transformed to: ;; (lambda (self n) (let-alias ((class (vector-ref self 0)) (a (vector-ref self 1)) (b (vector-ref self 2))) ;; (set! a (+ b n)))) (method->lambda (lambda(method-definition) (let ((arglist (cons 'self (cadr method-definition))) ; list of method's arguments (body (cddr method-definition))) ; body of the function ;; we `primitive-eval', because we don't want to have a function ;; definition (a list), but a function itself. This is guile-specific solution. (primitive-eval `(lambda ,arglist (let-alias ,context ,@body))))))) (set! methods (list->vector (map method->lambda member-functions))))) definition)) (define-macro (in object method) `(let* ((class (vector-ref ,object 0)) (name-to-method-map (vector-ref class 1)) (methods (vector-ref class 2)) (method-index (hash-ref name-to-method-map (car ,method))) (member-function (vector-ref methods method-index))) (apply member-function (cons ,object (cdr ,method))))) (define-macro (get object property) `(let* ((class (vector-ref ,object 0)) (name-to-value-map (vector-ref class 0)) (property-index (hash-ref name-to-value-map ,property))) (vector-ref ,object property-index))) (define (instance-of class . initial) (let* ((l (length (hash-map->list cons (vector-ref class 0)))) (object (make-vector l))) (vector-set! object 0 class) (if (> (length initial) (- l 1)) (set! initial (list-head initial (- l 1)))) (let* ((count (let ((c 0)) (lambda () (set! c (+ c 1)) c)))) (map (lambda(value)(vector-set! object (count) value)) initial)) object)) ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: SOS: Simple Object System 2008-09-13 22:42 SOS: Simple Object System Maciek Godek @ 2008-09-14 10:22 ` Neil Jerram 2008-09-14 11:21 ` Greg Troxel 2008-09-15 6:48 ` Andy Wingo 2 siblings, 0 replies; 16+ messages in thread From: Neil Jerram @ 2008-09-14 10:22 UTC (permalink / raw) To: Maciek Godek; +Cc: guile-user Hi Maciek, Thanks for sharing this! 2008/9/14 Maciek Godek <pstrychuj@gmail.com>: > Hi, > Using some hints you gave me, I've implemented a really tiny > object system -- and I would like to know your opinion ("why > it's still better to use goops" :D) You have already given a good summary of the pros and cons yourself, below. > It has, as I can > tell, a few advantages over goops -- mainly, storing objects > as vectors allows for an efficient and convenient object treating > from C level, so boatmen should be satisfied. > Secondly, people accustomed to the object.method() notation > (like myself) won't feel lost and the global namespace will be > kept clean. > The system certainly isn't as complex as goops and doesn't > handle types (in general) so exquisitely. Also, it's unable to > support multiple inheritance efficiently (single inheritance isn't > supported as well, but this could be done quite easily if needed), > but that's not my point. I think the only big thing you missed was GOOPS's level of customizability, which one you to create virtual slots, automatically define slots for classes of a particular metaclass, and such like. It's good to have another option than GOOPS. I imagine the major reason someone might choose to use SOS instead of GOOPS would be the C-level access. (And I hope we can one day work out something like that for GOOPS!) Regards, Neil ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: SOS: Simple Object System 2008-09-13 22:42 SOS: Simple Object System Maciek Godek 2008-09-14 10:22 ` Neil Jerram @ 2008-09-14 11:21 ` Greg Troxel 2008-09-15 6:48 ` Andy Wingo 2 siblings, 0 replies; 16+ messages in thread From: Greg Troxel @ 2008-09-14 11:21 UTC (permalink / raw) To: Maciek Godek; +Cc: guile-user [-- Attachment #1: Type: text/plain, Size: 285 bytes --] Your object system seems not to have a meta-object protocol. There is an interesting and important book about this subject, and it's worth reading if you haven't. http://en.wikipedia.org/wiki/The_Art_of_the_Metaobject_Protocol But, you said you are going for simple/less powerful. [-- Attachment #2: Type: application/pgp-signature, Size: 193 bytes --] ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: SOS: Simple Object System 2008-09-13 22:42 SOS: Simple Object System Maciek Godek 2008-09-14 10:22 ` Neil Jerram 2008-09-14 11:21 ` Greg Troxel @ 2008-09-15 6:48 ` Andy Wingo 2008-09-24 13:09 ` Maciek Godek 2 siblings, 1 reply; 16+ messages in thread From: Andy Wingo @ 2008-09-15 6:48 UTC (permalink / raw) To: Maciek Godek; +Cc: guile-user Howdy, On Sun 14 Sep 2008 00:42, "Maciek Godek" <pstrychuj@gmail.com> writes: > Hi, > Using some hints you gave me, I've implemented a really tiny > object system Neat! > your opinion ("why it's still better to use goops" :D) Use what you want :) But: > storing objects as vectors allows for an efficient and convenient > object treating from C level, so boatmen should be satisfied. GOOPS objects are internally implemented similar to vectors: http://wingolog.org/archives/2008/04/11/allocate-memory-part-of-n The only trick is that the mapping between slot names and indices in the slot array is not part of GOOPS' specification -- it depends on many things. But in normal cases, the first slot that you name in the class definition is stored in slot 0, etc: guile> (define-class <circle> () (radius #:init-keyword #:radius)) guile> (make <circle> #:radius 10) $1 = #<<circle> b7f8be20> guile> (struct-ref $2 0) $2 = 10 Of course from scheme the way to take advantage of this is to use the accessors, which compile down to this. But from C, probably your best bet is to introspect which index a slot is stored in at runtime, then cache that. From Guile-GNOME: /* from goops.c */ static int gtype_struct_offset (SCM class) { register SCM slots = SCM_SLOT (scm_class_of (class), scm_si_getters_n_setters); for (; !scm_is_null (slots); slots = SCM_CDR (slots)) if (SCM_CAAR (slots) == scm_sym_gtype) return scm_to_int (SCM_CDDR (SCM_CAR (slots))); scm_c_gruntime_error ("%gtype-class-bind", "`gtype' not allocated a slot in struct!", SCM_LIST1 (class)); return -1; } This could certainly be improved, somehow, on an API level. Andy -- http://wingolog.org/ ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: SOS: Simple Object System 2008-09-15 6:48 ` Andy Wingo @ 2008-09-24 13:09 ` Maciek Godek 2008-09-24 16:14 ` Ludovic Courtès ` (3 more replies) 0 siblings, 4 replies; 16+ messages in thread From: Maciek Godek @ 2008-09-24 13:09 UTC (permalink / raw) To: guile-user Thanks a lot for your all attention and clues. If it comes to GOOPS, I think it would be best to specify a well-defined C-level interface (for it would go with the spirit of guile). This is the one thing. The other is that in GOOPS a method is something different than what is commonly known in OOP, because a class doesn't know its methods (and furthermore, methods can be created at any time of program execution, not only during class definition). I'm not saying that it's good or bad (but it's quite confusing when a few similar but different notions share one name) There is also another issue concerning the fact that methods are available in global namespace -- the performance of the interpreter is always penalized by the type lookup (obviously, this doesn't have to be the case if the code is compiled) But the most important feature of OOP that is missed in GOOPS (because of global namespace methods) is the lack of the clean separation of interface and implementation in the way it's done in java, C# and the like. (At least that's what I think) Thanks again M. ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: SOS: Simple Object System 2008-09-24 13:09 ` Maciek Godek @ 2008-09-24 16:14 ` Ludovic Courtès 2008-09-24 18:00 ` Clinton Ebadi ` (2 subsequent siblings) 3 siblings, 0 replies; 16+ messages in thread From: Ludovic Courtès @ 2008-09-24 16:14 UTC (permalink / raw) To: guile-user Hi, "Maciek Godek" <pstrychuj@gmail.com> writes: > The other is that in GOOPS a method is something > different than what is commonly known in OOP, The design of GOOPS is based on that of CLOS, so GOOPS is surely familiar to anyone familiar with the CLOS flavor of OOP. :-) See http://en.wikipedia.org/wiki/CLOS for details. > because a class doesn't know its methods It does: guile> (length (class-methods <object>)) $4 = 54 But unlike in C++, Java, etc., a method is not bound to the type of its first argument: method dispatching is done on all arguments and on the number of arguments as well. > There is also another issue concerning the fact that > methods are available in global namespace That's not quite true: the namespace, be it for GOOPS methods ("generics" actually) or "regular" Scheme objects, is managed by the module system. Thus, it is possible to hide generics (and, consequently, the methods they contain) from users, simply by not exporting them from the module where they are defined. > But the most important feature of OOP that is missed > in GOOPS (because of global namespace methods) is the lack > of the clean separation of interface and implementation > in the way it's done in java, C# and the like. See above. Does that lessen your concerns? Thanks, Ludovic. ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: SOS: Simple Object System 2008-09-24 13:09 ` Maciek Godek 2008-09-24 16:14 ` Ludovic Courtès @ 2008-09-24 18:00 ` Clinton Ebadi 2008-09-24 21:04 ` Maciek Godek 2008-09-24 22:25 ` Jon Wilson 2008-09-24 22:45 ` Jon Wilson 3 siblings, 1 reply; 16+ messages in thread From: Clinton Ebadi @ 2008-09-24 18:00 UTC (permalink / raw) To: Maciek Godek; +Cc: guile-user "Maciek Godek" <pstrychuj@gmail.com> writes: > The other is that in GOOPS a method is something > different than what is commonly known in OOP, because > a class doesn't know its methods (and furthermore, > methods can be created at any time of program execution, > not only during class definition). I'm not saying that > it's good or bad (but it's quite confusing when a few similar > but different notions share one name) Interestingly enough, CLOS predates C++ and Java ;-) Separating classes and generic functions makes the language more powerful--now two orthogonal concepts may be combined in arbitrary ways. The classic example of having generic functions are multimethods wherein you can dispatch on the type of every argument of the generic. A simple example of this is the (simplified) present method from CLIM: (define-generic present (instance view)) Which then allows you to do nifty things like: (define-method (present (instance <image>) (view <text-view>)) (format #t "[~A]" (alt-text-of instance))) (define-method (present (instance <image>) (view <graphical-view>)) (display the image somehow)) etc. Doing this with a single-dispatch system is much less aesthetically pleasing. Note also that multimethods are only one of many advantages to having generic functions--they also enable method combinations and a few other things. Stylistically, they make the OO system integrate cleanly with the rest of the language rather than having its own specialized syntax for method invocation. > There is also another issue concerning the fact that > methods are available in global namespace -- the > performance of the interpreter is always penalized > by the type lookup (obviously, this doesn't have to > be the case if the code is compiled) Type lookup in GOOPS should be very fast--there are a few fairly simple implementation techniques that more or less eliminate the overhead of method dispatch (or at least turn it into a few very low overhead table lookups). /The Art of the Metaobject Protocol/ is a good inexpensive book that gives a decent overview of how to implement a fast CLOS. > But the most important feature of OOP that is missed > in GOOPS (because of global namespace methods) is the lack > of the clean separation of interface and implementation > in the way it's done in java, C# and the like. Actually, CLOS/GOOPS are perhaps the cleanest way to separate interface from implementation. You define a protocol as a set of generic functions and define methods upon them -- with no concern for the actual classes used with the protocol. In this way you can do implementation sharing via class inheritance or something akin to Java interfaces (if I understand them properly; I refuse to use such a language) and implement the protocol for arbitrary classes without having to arbitrarily force them to inherit from unrelated classes. -- Jessie: i stuck the phone antenna up the dogs nose and he ignored me ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: SOS: Simple Object System 2008-09-24 18:00 ` Clinton Ebadi @ 2008-09-24 21:04 ` Maciek Godek 2008-09-24 22:14 ` David Séverin ` (2 more replies) 0 siblings, 3 replies; 16+ messages in thread From: Maciek Godek @ 2008-09-24 21:04 UTC (permalink / raw) To: Clinton Ebadi; +Cc: guile-user 2008/9/24 Clinton Ebadi <clinton@unknownlamer.org>: > >> The other is that in GOOPS a method is something >> different than what is commonly known in OOP, because >> a class doesn't know its methods (and furthermore, >> methods can be created at any time of program execution, >> not only during class definition). I'm not saying that >> it's good or bad (but it's quite confusing when a few similar >> but different notions share one name) > > Interestingly enough, CLOS predates C++ and Java ;-) No wonder -- lambda calculus is a formal system to express concepts and you can express practically anything in it. C was invented to program von Neumann machines, and both C++ and Java are derivatives of C. Note however that both these languages were invented to address the particular needs of OOP and as such are well suited for that purpose (or at least that's what the most people think. CLOS is rarely used compared to C++ and Java -- can you explain why?) > Separating classes and generic functions makes the language more > powerful--now two orthogonal concepts may be combined in arbitrary > ways. The classic example of having generic functions are multimethods > wherein you can dispatch on the type of every argument of the > generic. A simple example of this is the (simplified) present method > from CLIM: > > (define-generic present (instance view)) > > Which then allows you to do nifty things like: > > (define-method (present (instance <image>) (view <text-view>)) > (format #t "[~A]" (alt-text-of instance))) > (define-method (present (instance <image>) (view <graphical-view>)) > (display the image somehow)) > > etc. And what about (define-method (present (zone <timezone>) (part-of-year <season>)) (define-method (present (santa <donor>) (child <acceptor>))) ? I mean of course these examples are artificial, but that's not their point :) (I won't expose it now to keep the reader in suspense, but stay tuned as it will certainly appear in the sequel) > Doing this with a single-dispatch system is much less aesthetically > pleasing. Note also that multimethods are only one of many advantages > to having generic functions--they also enable method combinations and > a few other things. Stylistically, they make the OO system integrate > cleanly with the rest of the language rather than having its own > specialized syntax for method invocation. I see your point, but I can't agree with it -- multimethods certainly cause ambiguity and make the code harder to read (you can't tell which method will be called unless you know the types of all its arguments). I've got a feeling that CLOS is an attempt to mimic synonymy that is present (yes, present!) in natural languages. Yet it causes a lot of confusion! Note that in C++like syntax, you always precede the name of the method with the object's name, and therefore you always specify the context for your expression. (the object is the context) This resembles the let form known from lisp, that is also used to build context. (No expression in the world is context-free, but the multimethods of CLOS seem to deny this simple truth) >> There is also another issue concerning the fact that >> methods are available in global namespace -- the >> performance of the interpreter is always penalized >> by the type lookup (obviously, this doesn't have to >> be the case if the code is compiled) > > Type lookup in GOOPS should be very fast--there are a few fairly > simple implementation techniques that more or less eliminate the > overhead of method dispatch (or at least turn it into a few very low > overhead table lookups). /The Art of the Metaobject Protocol/ is a > good inexpensive book that gives a decent overview of how to implement > a fast CLOS. I'm not arguing about this -- especially that there's great conceptual gain that results with this sort of elasticity. (Performance is the last thing I care about right now. But I hope you're right :>) >> But the most important feature of OOP that is missed >> in GOOPS (because of global namespace methods) is the lack >> of the clean separation of interface and implementation >> in the way it's done in java, C# and the like. > > Actually, CLOS/GOOPS are perhaps the cleanest way to separate > interface from implementation. You define a protocol as a set of > generic functions and define methods upon them -- with no concern for > the actual classes used with the protocol. The disadvantage is that (unlike in Java, C# etc.) the "interface" isn't an explicit object. I agree that this can be overcome with a proper discipline imposed on source code, but the documentation of GOOPS makes me think that no such discipline has yet been developed. > In this way you can do implementation sharing via class inheritance or > something akin to Java interfaces (if I understand them properly; I > refuse to use such a language) and implement the protocol for > arbitrary classes without having to arbitrarily force them to inherit > from unrelated classes. I don't quite get what you mean (I'd need an example). BTW Java seems to gain popularity instead of loosing it. (And I think that stupidity of mankind and human ignorance are not the only reasons) I admit that my arguments are somewhat abstract -- I haven't written anything using GOOPS or CLOS, only read some documentation (and although my mind was initially tabula rasa, but as I was getting deeper into that forest, I kept having more and more doubts. Maybe it's because I knew C++ before GOOPS?) Best regards M. ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: SOS: Simple Object System 2008-09-24 21:04 ` Maciek Godek @ 2008-09-24 22:14 ` David Séverin 2008-09-24 22:38 ` Clinton Ebadi 2008-09-25 13:58 ` David Séverin 2 siblings, 0 replies; 16+ messages in thread From: David Séverin @ 2008-09-24 22:14 UTC (permalink / raw) To: Maciek Godek; +Cc: Clinton Ebadi, guile-user Le Wed, 24 Sep 2008 23:04:51 +0200, "Maciek Godek" <pstrychuj@gmail.com> a écrit : > Note however that both these languages were invented to address > the particular needs of OOP and as such are well suited for that purpose > (or at least that's what the most people think. CLOS is rarely used > compared to C++ and Java -- can you explain why?) because most people are ... and 'nobody will ever be killed to propose the use of C++ and java ...' people like to conform to others, like your question shows, are you under some kind of industrial pressure ? : who says, in a scientific community, that a system is 'good' because 'most people uses it' ? I personally think that, from a grammar and semantic point of view, CLOS and GOOP are superior, by far, to other OOP systems, as the few responses on this list pointed out [but there are a lot more to say and articles to read about this matter] IMHO david ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: SOS: Simple Object System 2008-09-24 21:04 ` Maciek Godek 2008-09-24 22:14 ` David Séverin @ 2008-09-24 22:38 ` Clinton Ebadi 2008-09-25 23:03 ` Linas Vepstas 2008-09-26 14:20 ` Maciek Godek 2008-09-25 13:58 ` David Séverin 2 siblings, 2 replies; 16+ messages in thread From: Clinton Ebadi @ 2008-09-24 22:38 UTC (permalink / raw) To: Maciek Godek; +Cc: guile-user "Maciek Godek" <pstrychuj@gmail.com> writes: > 2008/9/24 Clinton Ebadi <clinton@unknownlamer.org>: >> Interestingly enough, CLOS predates C++ and Java ;-) > > No wonder -- lambda calculus is a formal system to express concepts > and you can express practically anything in it. C was invented to program > von Neumann machines, and both C++ and Java are derivatives of C. C predates Common Lisp and any Lisp object system :-) Note that the OO features of C++ are *not* derived from C but rather from Simula. > Note however that both these languages were invented to address > the particular needs of OOP and as such are well suited for that purpose > (or at least that's what the most people think. CLOS is rarely used > compared to C++ and Java -- can you explain why?) Popularity as a measure of quality is a fallacious argument (one that many people often use). Java's widespread adoption can be explained by Sun heavily promoting it with their deep pockets, and C++ as being an extension of C and coming from Bell Labs. Remember that Lisp was not usable on workstations and personal computers until the 90s and the Lisp machines of hte 70s and 80s had a drastically different OS compared to UNIX. As such it has only been in the last ten years that Common Lisp/Scheme have become usable for tasks that C++/Java/etc are used for. There are *very* large systems--ITA's airline ticket finding system is the canonical example of a thriving Lisp system. Lisp was traditionally used for things like expert systems, planners, CAD, etc. The first two are still not done well by either C++ or Java. >> Separating classes and generic functions makes the language more >> powerful--now two orthogonal concepts may be combined in arbitrary >> ways. The classic example of having generic functions are multimethods >> wherein you can dispatch on the type of every argument of the >> generic. A simple example of this is the (simplified) present method >> from CLIM: >> >> (define-generic present (instance view)) >> >> Which then allows you to do nifty things like: >> >> (define-method (present (instance <image>) (view <text-view>)) >> (format #t "[~A]" (alt-text-of instance))) >> (define-method (present (instance <image>) (view <graphical-view>)) >> (display the image somehow)) >> >> etc. > > And what about > (define-method (present (zone <timezone>) (part-of-year <season>)) > (define-method (present (santa <donor>) (child <acceptor>))) > ? What would the timezone method do? Perhaps you meant: (define-generic present-time-zone? (part-of-year)) As it doesn't make much sense to supply the answer to the predicate as the first argument (unless you meant something). The other example is solvable via namespaces: You can have a clim and a gift module, and then reference them as clim:present/gift:present. The guile syntax for doing this is not so nice now--((@ (clim) present) ...), but it doesn't have to be (and you can always use a #:renamer with use-modules). >> Doing this with a single-dispatch system is much less aesthetically >> pleasing. Note also that multimethods are only one of many advantages >> to having generic functions--they also enable method combinations and >> a few other things. Stylistically, they make the OO system integrate >> cleanly with the rest of the language rather than having its own >> specialized syntax for method invocation. > > I see your point, but I can't agree with it -- multimethods certainly > cause ambiguity and make the code harder to read (you can't tell > which method will be called unless you know the types of all its > arguments). The point of OO methods is that you need not concern yourself with which method is called: every method on a generic has the same behavior. If it does not then it violates the protocol, and you can certainly do this in a single dispatch system as well. >>> But the most important feature of OOP that is missed >>> in GOOPS (because of global namespace methods) is the lack >>> of the clean separation of interface and implementation >>> in the way it's done in java, C# and the like. >> >> Actually, CLOS/GOOPS are perhaps the cleanest way to separate >> interface from implementation. You define a protocol as a set of >> generic functions and define methods upon them -- with no concern for >> the actual classes used with the protocol. > > The disadvantage is that (unlike in Java, C# etc.) the "interface" isn't an > explicit object. I agree that this can be overcome with a proper discipline > imposed on source code, but the documentation of GOOPS makes me > think that no such discipline has yet been developed. This is a bit of an open problem even if the other languages. You can specify a collective interface in Java (or a mixin class in C++), but you still cannot specify the required behavior of the protocol except in an ad hoc fashion. This is a problem that may never be solved (and is perhaps a sign that OO is not so great). You could, of course, add packaged protocol interfaces to GOOPS using the MOP and a few macros: (define-protocol-interface NAME (define-generic ...) ...) (define-protocol-implementation NAME CLASS (define-method ...) ...) Along with some metaclass magic to ensure that the entire protocol is indeed defined withing the `define-protocol-implementation' block. The benefits of this, however, are dubious as you still cannot guarantee anything about the behavior of the implementation in a programmatic way. >> In this way you can do implementation sharing via class inheritance or >> something akin to Java interfaces (if I understand them properly; I >> refuse to use such a language) and implement the protocol for >> arbitrary classes without having to arbitrarily force them to inherit >> from unrelated classes. > > I don't quite get what you mean (I'd need an example). > BTW Java seems to gain popularity instead of loosing it. > (And I think that stupidity of mankind and human ignorance > are not the only reasons) Say that you have a system wherein objects can move (obviously an artificially simple example): (define-generic move (thing point)) Now say that you have machines, animals, etc. In a Smalltalkesque OO system you would need to do something akin to: (define-class movable-object () (#:methods (move (thing point) ...) ...) ...) (define-class machine (... movable-object ...) ...) (define-class animal (... movable-object ...) ...) Taxonimically animals and machines are *not* related by their ability to move, but they can both move. Thus you run into a problem with your type discipline as a result. In a language with orthogonal generics and classes you can simply implement the `move' method for anything that can move without polluting your class heirarchy. This is especially important if you are doing taxonomic reasoning of any sort. Now, you may perhaps raise the objection: "But how would I tell which classes specialized `move'?" In CLOS at least (I am not quite familiar enough with the GOOPS internals) you can query the generic function object for a list of classes that specialize any of its arguments since the MOP guarantees that this information will be maintained. I hope this clears things up a bit. -- "Karen loved animals. Unfortunately the cheetahs betrayed her trust," Libot said. ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: SOS: Simple Object System 2008-09-24 22:38 ` Clinton Ebadi @ 2008-09-25 23:03 ` Linas Vepstas 2008-09-26 14:20 ` Maciek Godek 1 sibling, 0 replies; 16+ messages in thread From: Linas Vepstas @ 2008-09-25 23:03 UTC (permalink / raw) To: Clinton Ebadi; +Cc: guile-user 2008/9/24 Clinton Ebadi <clinton@unknownlamer.org>: > This is a bit of an open problem even if the other languages. You can > specify a collective interface in Java (or a mixin class in C++), but > you still cannot specify the required behavior of the protocol except > in an ad hoc fashion. This is a problem that may never be solved (and > is perhaps a sign that OO is not so great). There are certainly many other problems with the OO paradigm. I have coded in Java, and one of its greatest failings is that it *forces* you to associate every function to some object -- It forces you into designing interfaces even when you are only interested in implementation. This is not a problem for some 90% of all the functions one typically ahs to create in some project. However, during architecture, design, development, there's always a few "tricky" areas, where its simply not clear where to implement some function -- there may be several choices, all not very good, etc. However, Java *forces* you to stick such functions into a class, some class, any class, even if they don't really belong there. And once you do that, the next thing you know, they are so tightly tied in, that it becomes impossible (well, overwhelmingly difficult) to refactor the code. This is a variant of the so-called "quick-setting concrete" effect seen in C++. In real life, design needs to be more flexible, more moldable, and code needs to be easy to change. Many object systems seem to make a point of inhibiting design change, by forcing you design (and use) an interface before you are intellectually ready to design the interface. --linas ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: SOS: Simple Object System 2008-09-24 22:38 ` Clinton Ebadi 2008-09-25 23:03 ` Linas Vepstas @ 2008-09-26 14:20 ` Maciek Godek 1 sibling, 0 replies; 16+ messages in thread From: Maciek Godek @ 2008-09-26 14:20 UTC (permalink / raw) To: guile-user 2008/9/25 Clinton Ebadi <clinton@unknownlamer.org>: >> No wonder -- lambda calculus is a formal system to express concepts >> and you can express practically anything in it. C was invented to program >> von Neumann machines, and both C++ and Java are derivatives of C. > > C predates Common Lisp and any Lisp object system :-) Note that the OO > features of C++ are *not* derived from C but rather from Simula. I didn't know that. I meant that they adopt machine model from C. (that's is quite strange a combination, making C++ very incoherent) >> Note however that both these languages were invented to address >> the particular needs of OOP and as such are well suited for that purpose >> (or at least that's what the most people think. CLOS is rarely used >> compared to C++ and Java -- can you explain why?) > > Popularity as a measure of quality is a fallacious argument (one that > many people often use). Java's widespread adoption can be explained by > Sun heavily promoting it with their deep pockets, and C++ as being an > extension of C and coming from Bell Labs. C++ is the deepest septic tank I've ever fallen into :) Fortunately, these approaches weren't successful. OK -- java is actually used to code games on mobile phones, but the most of the projects on sourceforge are programmed in C (thus avoiding all the problems generated by the handicapped object system of C++) > Remember that Lisp was not usable on workstations and personal > computers until the 90s and the Lisp machines of hte 70s and 80s had a > drastically different OS compared to UNIX. As such it has only been in > the last ten years that Common Lisp/Scheme have become usable for > tasks that C++/Java/etc are used for. There are *very* large > systems--ITA's airline ticket finding system is the canonical example > of a thriving Lisp system. That's a good point -- in C there arel programs, and in Lisp -- systems (or organisms, as the authors of SICP would say) Now the situation of Lisp seems much clearer to me. Unfortunately the coding style in lisp is still strongly diversified, there are too many OO systems and practically no standards (CLOS is probably nearly a standard, GOOPS is available in guile ony). C has become very common; for Java, there's one official SDK that is a good starting point for everyone who's interested. If you're willing to program in Scheme, there are many choices (I guess PLT is good to start with, but I'm afraid it also has its limitations) There are still some features guile is lacking: firstly, there is no simple way to call C code from the level of guile -- you have to write frequently trivial wrappers to make it work, while having a C parser and a single wrapper on dlfcn library would suffice (you could then acquire symbols from header files and link them with appropriate DL objects -- this way, guile would obtain the frequently advertised feature of C++ -- the ability to call C functions directly) The second thing is the performance issue: you can't compile directly to machine code (on the fly), and the practice of byte-compiling (with guile-vm) is still avaliable for the chosen ones, but I'm really glad to see Andy's efforts to set it all up. (Thank you, Andy!) Guile, however, offers the level of openness and extensibility that allows it to be constantly improved (and that lessens my concerns) > Lisp was traditionally used for things like expert systems, planners, > CAD, etc. The first two are still not done well by either C++ or Java. Java is quite good for web applets and the aforementioned moblie phones, and C++ is really great in causing trouble and annoying people. Scheme was never meant for that purpose (but I think that's doable) >>> (define-generic present (instance view)) >>> >>> Which then allows you to do nifty things like: >>> >>> (define-method (present (instance <image>) (view <text-view>)) >>> (format #t "[~A]" (alt-text-of instance))) >>> (define-method (present (instance <image>) (view <graphical-view>)) >>> (display the image somehow)) >>> >>> etc. >> >> And what about >> (define-method (present (zone <timezone>) (part-of-year <season>)) >> (define-method (present (santa <donor>) (child <acceptor>))) >> ? > > What would the timezone method do? Perhaps you meant: > > (define-generic present-time-zone? (part-of-year)) > > As it doesn't make much sense to supply the answer to the predicate as > the first argument (unless you meant something). Well, never mind that (I actually meant a method that returns present time in given timezone, but I wrote it slightly thoughtlessly, hence the part-of-year argument) > The other example is solvable via namespaces: You can have a clim and > a gift module, and then reference them as > clim:present/gift:present. The guile syntax for doing this is not so > nice now--((@ (clim) present) ...), but it doesn't have to be (and you > can always use a #:renamer with use-modules). I'm getting to like the whole idea of modules more and more :) >>> Doing this with a single-dispatch system is much less aesthetically >>> pleasing. Note also that multimethods are only one of many advantages >>> to having generic functions--they also enable method combinations and >>> a few other things. Stylistically, they make the OO system integrate >>> cleanly with the rest of the language rather than having its own >>> specialized syntax for method invocation. >> >> I see your point, but I can't agree with it -- multimethods certainly >> cause ambiguity and make the code harder to read (you can't tell >> which method will be called unless you know the types of all its >> arguments). > > The point of OO methods is that you need not concern yourself with > which method is called: every method on a generic has the same > behavior. If it does not then it violates the protocol, and you can > certainly do this in a single dispatch system as well. As for me, the advantage of classes is that they gather operations that you can perform on an object in one place (object's class definition). This way, the documentation of source code is really well structured. (Besides it is a matter of thinking about it: I agree that when you rotate a box in the air, you rotate box, not box.rotate(), but when you push play button on VCR, then you VCR.play()) - Pokaż cytowany tekst - >>>> But the most important feature of OOP that is missed >>>> in GOOPS (because of global namespace methods) is the lack >>>> of the clean separation of interface and implementation >>>> in the way it's done in java, C# and the like. >>> >>> Actually, CLOS/GOOPS are perhaps the cleanest way to separate >>> interface from implementation. You define a protocol as a set of >>> generic functions and define methods upon them -- with no concern for >>> the actual classes used with the protocol. >> >> The disadvantage is that (unlike in Java, C# etc.) the "interface" isn't an >> explicit object. I agree that this can be overcome with a proper discipline >> imposed on source code, but the documentation of GOOPS makes me >> think that no such discipline has yet been developed. > > This is a bit of an open problem even if the other languages. You can > specify a collective interface in Java (or a mixin class in C++), but > you still cannot specify the required behavior of the protocol except > in an ad hoc fashion. This is a problem that may never be solved (and > is perhaps a sign that OO is not so great). > > You could, of course, add packaged protocol interfaces to GOOPS using > the MOP and a few macros: > > (define-protocol-interface NAME > (define-generic ...) ...) > > (define-protocol-implementation NAME CLASS > (define-method ...) ...) > > Along with some metaclass magic to ensure that the entire protocol is > indeed defined withing the `define-protocol-implementation' block. The > benefits of this, however, are dubious as you still cannot guarantee > anything about the behavior of the implementation in a programmatic > way. Yeah, guess you're right. Maybe this multiplicity of choices and lack of common solutions on many fields makes scheme programming harder. >>> In this way you can do implementation sharing via class inheritance or >>> something akin to Java interfaces (if I understand them properly; I >>> refuse to use such a language) and implement the protocol for >>> arbitrary classes without having to arbitrarily force them to inherit >>> from unrelated classes. >> >> I don't quite get what you mean (I'd need an example). >> BTW Java seems to gain popularity instead of loosing it. >> (And I think that stupidity of mankind and human ignorance >> are not the only reasons) > > Say that you have a system wherein objects can move (obviously an > artificially simple example): Oh, at last, an example! :) > (define-generic move (thing point)) > > Now say that you have machines, animals, etc. In a Smalltalkesque OO > system you would need to do something akin to: > > (define-class movable-object () > (#:methods (move (thing point) ...) > ...) ...) > (define-class machine (... movable-object ...) > ...) > (define-class animal (... movable-object ...) > ...) > > Taxonimically animals and machines are *not* related by their ability > to move, but they can both move. Thus you run into a problem with your > type discipline as a result. In a language with orthogonal generics > and classes you can simply implement the `move' method for anything > that can move without polluting your class heirarchy. This is > especially important if you are doing taxonomic reasoning of any sort. You've convinced me -- MOP certainly gives more flexibility. It doesn't structure the way you program, and doesn't take you by the hand (which is sometimes desirable, especially when you begin). > Now, you may perhaps raise the objection: "But how would I tell which > classes specialized `move'?" In CLOS at least (I am not quite familiar > enough with the GOOPS internals) you can query the generic function > object for a list of classes that specialize any of its arguments > since the MOP guarantees that this information will be maintained. > > I hope this clears things up a bit. It certainly does. Thanks. ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: SOS: Simple Object System 2008-09-24 21:04 ` Maciek Godek 2008-09-24 22:14 ` David Séverin 2008-09-24 22:38 ` Clinton Ebadi @ 2008-09-25 13:58 ` David Séverin 2008-09-25 17:17 ` Maciek Godek 2 siblings, 1 reply; 16+ messages in thread From: David Séverin @ 2008-09-25 13:58 UTC (permalink / raw) To: Maciek Godek; +Cc: Clinton Ebadi, guile-user Le Wed, 24 Sep 2008 23:04:51 +0200, "Maciek Godek" <pstrychuj@gmail.com> a écrit : > ... > Note however that both these languages were invented to address > the particular needs of OOP and as such are well suited for that purpose > (or at least that's what the most people think. CLOS is rarely used > compared to C++ and Java -- can you explain why?) also because people in command sometimes have fear to take their responsability: here in Rio de Janeiro, 2 years ago, at PUC University, the scheme course has been canceled [for ever] because ... students didn't want to be teached scheme anymore ?!? so, 18 years old kids now decide what they should be teached at university level ... and guess what they 'quasy all' want ... this leads to a very 'dangerous' standardization of computer technique skills available at industrial level, lack of creativity [creativity is the rule, not the execption, but people need to be motivated and teached to trust themselves they are creative, and in our field, computer science, scheme is [also but can not be reduced to this only off course] an excellent creativity trigger. in my original town in Belgium, Ouindoze offered [24 years ago] that the operating system course at university be based on their system [fortunatly this was refused] then they would offer the material and licenses ... so that 'people would already be ready to work when quitting university' and would not need training when they start working ... blabla cost effective for the society ... blabla blablabla it's like wine: big companies purchased small ones, private small wine producer, and converted the taste of the small producer to the standard taste, result: you here in the population, that the wine is good if it taste like the others [and they now and since may years already change the taste chemically] david ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: SOS: Simple Object System 2008-09-25 13:58 ` David Séverin @ 2008-09-25 17:17 ` Maciek Godek 0 siblings, 0 replies; 16+ messages in thread From: Maciek Godek @ 2008-09-25 17:17 UTC (permalink / raw) To: David Séverin; +Cc: guile-user 2008/9/25 David Séverin <david@altosw.be>: >> (or at least that's what the most people think. CLOS is rarely used >> compared to C++ and Java -- can you explain why?) > > also because people in command sometimes have fear to take their > responsability: here in Rio de Janeiro, 2 years ago, at PUC University, the > scheme course has been canceled [for ever] because ... students didn't > want to be teached scheme anymore ?!? > > so, 18 years old kids now decide what they should be teached at > university level ... and guess what they 'quasy all' want ... > > this leads to a very 'dangerous' standardization of computer technique skills > available at industrial level, lack of creativity [creativity is the rule, not > the execption, but people need to be motivated and teached to trust themselves > they are creative, and in our field, computer science, scheme is [also but can > not be reduced to this only off course] an excellent creativity trigger. The difference between, say, C and lisp is that C is intended for programming computers, and lisp is a notation for programming in general (you don't have any implicit memory model -- conversely, lambda calculus is probably the most universal way to express algorithm). This is visible when you compare "Structure and Interpretation.." or "How to design programs" to "The C Programming Language" -- it seems that schemers are aware that programs are present not only inside of computers, but wherever some sort of control is. On the other hand, people prefer braces and infix notation to express computer programs -- probably because it's the notation they got used to on their math classes. > in my original town in Belgium, Ouindoze offered [24 years ago] that the > operating system course at university be based on their system [fortunatly this > was refused] then they would offer the material and licenses ... so that > 'people would already be ready to work when quitting university' and would not > need training when they start working ... blabla cost effective for the > society ... blabla blablabla :] Yes, that's a clever way to utilize public money. (And that's funny about software that it really costs nothing to give you this license). I'd love to complain on the actions of microsoft and praise greatness of freebsd, but it's not the proper place :( > it's like wine: big companies purchased small ones, private small wine > producer, and converted the taste of the small producer to the standard taste, > result: you here in the population, that the wine is good if it taste like the > others [and they now and since may years already change the taste chemically] standardized men drinking only corporate wine and programming standardized applications in java, having their lives perfectly predicted before they were even born. let's not drink for them :) ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: SOS: Simple Object System 2008-09-24 13:09 ` Maciek Godek 2008-09-24 16:14 ` Ludovic Courtès 2008-09-24 18:00 ` Clinton Ebadi @ 2008-09-24 22:25 ` Jon Wilson 2008-09-24 22:45 ` Jon Wilson 3 siblings, 0 replies; 16+ messages in thread From: Jon Wilson @ 2008-09-24 22:25 UTC (permalink / raw) To: guile-user Hi, You might be interested to read Jonathan Rees' take on OO. It certainly broadens the mind regarding the various implementations and terminology of OO, but is still quite brief. I certainly don't think the Java/C++ model is the last word in OO (but I didn't think that before reeding Rees, either) http://www.paulgraham.com/reesoo.html Regards, Jon Maciek Godek wrote: > Thanks a lot for your all attention and clues. > > If it comes to GOOPS, I think it would be best to > specify a well-defined C-level interface (for it would > go with the spirit of guile). This is the one thing. > > The other is that in GOOPS a method is something > different than what is commonly known in OOP, because > a class doesn't know its methods (and furthermore, > methods can be created at any time of program execution, > not only during class definition). I'm not saying that > it's good or bad (but it's quite confusing when a few similar > but different notions share one name) > > There is also another issue concerning the fact that > methods are available in global namespace -- the > performance of the interpreter is always penalized > by the type lookup (obviously, this doesn't have to > be the case if the code is compiled) > > But the most important feature of OOP that is missed > in GOOPS (because of global namespace methods) is the lack > of the clean separation of interface and implementation > in the way it's done in java, C# and the like. > > (At least that's what I think) > > Thanks again > M. > > ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: SOS: Simple Object System 2008-09-24 13:09 ` Maciek Godek ` (2 preceding siblings ...) 2008-09-24 22:25 ` Jon Wilson @ 2008-09-24 22:45 ` Jon Wilson 3 siblings, 0 replies; 16+ messages in thread From: Jon Wilson @ 2008-09-24 22:45 UTC (permalink / raw) To: guile-user Hi again, For an example of an OO system that is even more wildly different, but still quite interestingly useful, look up the Prometheus object system for Scheme. I don't know if there is a version that would happily run on Guile, but there are versions for at least Scheme48 and PLT, IIRC. It is prototype based, and really quite fascinating. Regards, Jon Maciek Godek wrote: > Thanks a lot for your all attention and clues. > > If it comes to GOOPS, I think it would be best to > specify a well-defined C-level interface (for it would > go with the spirit of guile). This is the one thing. > > The other is that in GOOPS a method is something > different than what is commonly known in OOP, because > a class doesn't know its methods (and furthermore, > methods can be created at any time of program execution, > not only during class definition). I'm not saying that > it's good or bad (but it's quite confusing when a few similar > but different notions share one name) > > There is also another issue concerning the fact that > methods are available in global namespace -- the > performance of the interpreter is always penalized > by the type lookup (obviously, this doesn't have to > be the case if the code is compiled) > > But the most important feature of OOP that is missed > in GOOPS (because of global namespace methods) is the lack > of the clean separation of interface and implementation > in the way it's done in java, C# and the like. > > (At least that's what I think) > > Thanks again > M. > > ^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2008-09-26 14:20 UTC | newest] Thread overview: 16+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2008-09-13 22:42 SOS: Simple Object System Maciek Godek 2008-09-14 10:22 ` Neil Jerram 2008-09-14 11:21 ` Greg Troxel 2008-09-15 6:48 ` Andy Wingo 2008-09-24 13:09 ` Maciek Godek 2008-09-24 16:14 ` Ludovic Courtès 2008-09-24 18:00 ` Clinton Ebadi 2008-09-24 21:04 ` Maciek Godek 2008-09-24 22:14 ` David Séverin 2008-09-24 22:38 ` Clinton Ebadi 2008-09-25 23:03 ` Linas Vepstas 2008-09-26 14:20 ` Maciek Godek 2008-09-25 13:58 ` David Séverin 2008-09-25 17:17 ` Maciek Godek 2008-09-24 22:25 ` Jon Wilson 2008-09-24 22:45 ` Jon Wilson
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).