I'd like to implement this:
(defmyclass foo1 :extends foo0
"This is documentation for foo1 class"
(:public :static
memberstatic1 :init 'value)
(:protected
member1 :type symbol :init 'member1 :doc "Documentation for member1"
member2)
(:public
method1 :method (((arg1 number) (arg2 number))
(if (< arg1 arg2)
this.member1
this.member2))
method1 :method (() this.member1)
:constructor (() nil)
:constructor (((arg1 symbol))
(setf this.member2 arg1))))
(defvar *foo* (new foo1 'example-arg))
(print *foo*.member2) ;error, it is protected
(foo1.method1) ;error, foo1 is not an instance
(print foo1.memberstatic1) ; 'value
(print (*foo*.method1 2 3)) ; 'member1
So I have a similar object system to Java. I want it to be 100%
compatible with CLOS, so I can interchange classes from one system to
another. My main problems are:
- Passing different number of arguments to methods while remaining fully
polymorphic.
- The same with constructors.
- Modify the reader to accept the "instance.member/method" syntax.
- Accept the "this" keyword.
So, I accept any kind of sugerence, (but please don't insult/be rude, as
people here tend to be, that kind of messages will be ignored).
Hello
On Mar 12, 9:03 am, Javier <·······@gmail.com> wrote:
> I'd like to implement this:
>
> (defmyclass foo1 :extends foo0
> "This is documentation for foo1 class"
> (:public :static
> memberstatic1 :init 'value)
> (:protected
> member1 :type symbol :init 'member1 :doc "Documentation for member1"
> member2)
> (:public
> method1 :method (((arg1 number) (arg2 number))
> (if (< arg1 arg2)
> this.member1
> this.member2))
> method1 :method (() this.member1)
> :constructor (() nil)
> :constructor (((arg1 symbol))
> (setf this.member2 arg1))))
>
> (defvar *foo* (new foo1 'example-arg))
>
> (print *foo*.member2) ;error, it is protected
>
> (foo1.method1) ;error, foo1 is not an instance
>
> (print foo1.memberstatic1) ; 'value
>
> (print (*foo*.method1 2 3)) ; 'member1
>
> So I have a similar object system to Java. I want it to be 100%
> compatible with CLOS, so I can interchange classes from one system to
> another.
As per my previous responses to you, the first question is "why?" It
simply looks to me that you want to have a surface (or "concrete")
syntax that is the closest possible to Java. My question to you is
why I cannot have the following in Java
public Integer method factorial(Integer x) {
if (equals(x, 0)) 1 else x * factorial(x - 1);
}
The reason I do not even ask this question (and I did for other
reasons and with a different answer: do a Google search for Jester
Esterel), is that each language has its own look-n-feel. Having said
that, you question is ok as long as you were willing (which does not
look you are) to make some concessions to the underlying language.
Let's suppose to change your "input language" as follows
(incidentally: you are not asking for CLOS a la Java, but for CLOS a
la C++; cfr, the scope of your :protected, :private, and :public
sections).
(def-clava-class foo1 :extends foo0
"This is documentation for foo1 class"
(:public memberstatic1 :static t :init 'value)
(:protected member1 :type symbol :init 'member1 :doc "Documentation
for member1")
(:protected member2)
(:public method1 :method ((arg1 number) (arg2 number))
(if (< arg1 arg2)
this.member1
this.member2))
(:public method1 :method () this.member1)
(:constructor () nil)
(:constructor ((arg1 symbol))
(setf this.member2 arg1)))
> My main problems are:
>
> - Passing different number of arguments to methods while remaining fully
> polymorphic.
Build a trampoline.
> - The same with constructors.
See above.
> - Modify the reader to accept the "instance.member/method" syntax.
THOU SHALT NOT DO THAT. Don't even think about it. I am not asking
Java to accept the sintax
member_x of member_y of instance42;
However, note that WITHIN METHOD BODIES you can do that.... and other
things as well.
> - Accept the "this" keyword.
Done.
>
> So, I accept any kind of sugerence, (but please don't insult/be rude, as
> people here tend to be, that kind of messages will be ignored).
Will this suffice? Of course the CLAVA::DEF-CLAVA-CLASS macro is left
as an exercise for the Ruby Guy (thus adding to his homework
workload). I can send/post the code elsewhere.
CLAVA 101 > (pprint (macroexpand
'(def-clava-class foo1 :extends foo0
"This is documentation for foo1 class"
(:public memberstatic1 :static t :init 'value)
(:protected member1 :type symbol :init 'member1 :doc "Documentation
for member1")
(:protected member2)
(:public method1 :method ((arg1 number) (arg2 number))
(if (< arg1 arg2)
this.member1
this.member2))
(:public method1 :method () this.member1)
(:constructor () nil)
(:constructor ((arg1 symbol))
(setf this.member2 arg1)))))
(PROGN
(DEFCLASS FOO1
(FOO0)
((THIS.MEMBERSTATIC1
:TYPE
T
:INITFORM
'VALUE
:DOCUMENTATION
NIL
:ALLOCATION
:CLASS
:ACCESSOR
MEMBERSTATIC1)
(THIS.MEMBER1
:TYPE
SYMBOL
:INITFORM
'MEMBER1
:DOCUMENTATION
"Documentation for member1")
(THIS.MEMBER2 :TYPE T :INITFORM NIL :DOCUMENTATION NIL))
(:DOCUMENTATION "This is documentation for foo1 class"))
(SETF (GET 'FOO1 '%%%PRIVATE-SLOTS%%%) 'NIL
(GET 'FOO1 '%%%PUBLIC-SLOTS%%%) '(MEMBERSTATIC1)
(GET 'FOO1 '%%%PROTECTED-SLOTS%%%) '(MEMBER1 MEMBER2))
(DEFGENERIC NEW-FOO1 (LOOP REPEAT 1 COLLECT (GENSYM)))
(DEFMETHOD NEW-FOO1 ((THIS FOO1) #:ARG-10438) (WITH-SLOTS NIL THIS
NIL))
(DEFMETHOD NEW-FOO1 ((THIS FOO1) (ARG1 SYMBOL)) (WITH-SLOTS NIL THIS
(SETF THIS.MEMBER2 ARG1)))
(DEFMETHOD INITIALIZE-INSTANCE
:AFTER
((THIS FOO1) &KEY ARGS-FROM-NEW &ALLOW-OTHER-KEYS)
(APPLY #'NEW-FOO1 THIS (BUILD-VALUES-LIST 1 (COPY-LIST ARGS-FROM-
NEW))))
(DEFUN METHOD1 (THIS &REST ARGS)
(APPLY #'METHOD-METHOD1 THIS (BUILD-VALUES-LIST 2 (COPY-LIST
ARGS))))
(DEFMETHOD METHOD-METHOD1
((THIS FOO1) #:ARG-10440 #:ARG-10441)
(WITH-SLOTS NIL THIS THIS.MEMBER1))
(DEFMETHOD METHOD-METHOD1
((THIS FOO1) (ARG1 NUMBER) (ARG2 NUMBER))
(WITH-SLOTS NIL THIS (IF (< ARG1 ARG2) THIS.MEMBER1
THIS.MEMBER2)))
'FOO1)
Note that this is a 3 hours hack. The number of things that you will
not like is large and the number of ways it *will* fail is larger.
The semantics is not even close to Java, but it *can* be made close ot
it. In many ways the code is ugly CL, and I have not even brought in
the Metaobject Protocol. I have many other aces up my CL sleeve.
Having said that, you should appreciate the power of Communist Lisp
and maybe reconsider your approach to it. I know I am sounding
paternalistic.
Let me finish with a gripe of mine on "syntax". The syntax of Common
Lisp is amazingly simple and regular. It is all atoms or applications
or hash reader macros (which most of the time expand in applications)
or backquotes or quotes (which expand in (QUOTE ...)). Trying to
shoehorn the dot notation into CL is a *bad idea* (TM); the same goes
for other C/C++, SLDJ or Perlish constructs (after all, CLers like to
keep their self-esteem low). That is the reason why over the long CL
history you have seen very very very few libraries which do use
exogenous syntax by defining a slew of reader macros. And those that
do are (1) extremely careful about it and (2) do it for very good
reason; cfr FSet and CL-SQL.
Cheers
--
Marco
ELS 2009 www.european-lisp.symposium.org
Marco Antoniotti escribi�:
> Hello
>
> On Mar 12, 9:03 am, Javier <·······@gmail.com> wrote:
>> I'd like to implement this:
>>
>> (defmyclass foo1 :extends foo0
>> "This is documentation for foo1 class"
>> (:public :static
>> memberstatic1 :init 'value)
>> (:protected
>> member1 :type symbol :init 'member1 :doc "Documentation for member1"
>> member2)
>> (:public
>> method1 :method (((arg1 number) (arg2 number))
>> (if (< arg1 arg2)
>> this.member1
>> this.member2))
>> method1 :method (() this.member1)
>> :constructor (() nil)
>> :constructor (((arg1 symbol))
>> (setf this.member2 arg1))))
>>
>> (defvar *foo* (new foo1 'example-arg))
>>
>> (print *foo*.member2) ;error, it is protected
>>
>> (foo1.method1) ;error, foo1 is not an instance
>>
>> (print foo1.memberstatic1) ; 'value
>>
>> (print (*foo*.method1 2 3)) ; 'member1
>>
>> So I have a similar object system to Java. I want it to be 100%
>> compatible with CLOS, so I can interchange classes from one system to
>> another.
>
> As per my previous responses to you, the first question is "why?" It
> simply looks to me that you want to have a surface (or "concrete")
> syntax that is the closest possible to Java.
I was a Java moron, but appreciate Lisp interactivity and macros. I'm
not very purist, don't matter to mix different kind of codes, and the
Java (or c++, it doesn't matter) syntax seems to be more compact.
I'm really used to work with objects that way. The way that CLOS is made
doesn't fit very much with my style. But everybody says that Lisp CAN be
modified to adapt to you, so I'm just doing so.
This is the answer for the text you wrote that I'm going to cut down in
order to save space:
> My question to you [...]
> Will this suffice?
I apreciate it, thank you. But my main concern is not exactly how to
write the macros... I think I can do it, although probably not as fast
as you.
I asked mainly because of the instance.something notation.
> [...]
> Note that this is a 3 hours hack.
Wuaooo. I just wrote the skeleton in that time. But I'm just learning,
and finding the way to solve the evil instance.method notation...
> The number of things that you will
> not like is large and the number of ways it *will* fail is larger.
> The semantics is not even close to Java, but it *can* be made close ot
> it. In many ways the code is ugly CL, and I have not even brought in
> the Metaobject Protocol. I have many other aces up my CL sleeve.
>
> Having said that, you should appreciate the power of Communist Lisp
> and maybe reconsider your approach to it. I know I am sounding
> paternalistic.
>
> Let me finish with a gripe of mine on "syntax". The syntax of Common
> Lisp is amazingly simple and regular. It is all atoms or applications
> or hash reader macros (which most of the time expand in applications)
> or backquotes or quotes (which expand in (QUOTE ...)). Trying to
> shoehorn the dot notation into CL is a *bad idea* (TM); the same goes
> for other C/C++, SLDJ or Perlish constructs (after all, CLers like to
> keep their self-esteem low). That is the reason why over the long CL
> history you have seen very very very few libraries which do use
> exogenous syntax by defining a slew of reader macros. And those that
> do are (1) extremely careful about it and (2) do it for very good
> reason; cfr FSet and CL-SQL.
Do not agree very much with that... if I'm doing lisp is because Lisp
allows me to redefine the way the language works... for fixed languages
I already have Java, which is right if you have the right tools (i.e. a
good IDE).
So here comes my first problem. This is que skeleton until now (not
tested yet):
(defmacro defmyclass (name &body body)
(when (not (symbolp name)) (error "Invalid class name."))
(let*
((declaration-starts-at 0)
(extends (when (and (eq (first body) :entends)
(symbolp (second body)))
(incf declaration-starts-at 2)
(second body)))
(class-documentation
(let ((guess-doc (first (nthcdr declaration-starts-at body))))
(cond ((stringp guess-doc)
(incf declaration-starts-at)
guess-doc)
(t ""))))
(declarations (nthcdr declaration-starts-at))
(members
)
(generics
nil)
(methods
))
`(progn
(defclass ,name (,extends)
,members
(:documentation ,class-documentation))
,@generics
,@methods)))
My first problem comes here from the fact that before writing the code
that writes members, generics and methods, I must teach the compiler
reader to read the notation "instance.method/member".
Any help?
Javier escribi�:
> I'd like to implement this:
>
> (defmyclass foo1 :extends foo0
> "This is documentation for foo1 class"
> (:public :static
> memberstatic1 :init 'value)
> (:protected
> member1 :type symbol :init 'member1 :doc "Documentation for member1"
> member2)
> (:public
> method1 :method (((arg1 number) (arg2 number))
> (if (< arg1 arg2)
> this.member1
> this.member2))
> method1 :method (() this.member1)
> :constructor (() nil)
> :constructor (((arg1 symbol))
> (setf this.member2 arg1))))
>
> (defvar *foo* (new foo1 'example-arg))
>
> (print *foo*.member2) ;error, it is protected
>
> (foo1.method1) ;error, foo1 is not an instance
>
> (print foo1.memberstatic1) ; 'value
>
> (print (*foo*.method1 2 3)) ; 'member1
>
>
>
> So I have a similar object system to Java. I want it to be 100%
> compatible with CLOS, so I can interchange classes from one system to
> another. My main problems are:
>
> - Passing different number of arguments to methods while remaining fully
> polymorphic.
> - The same with constructors.
> - Modify the reader to accept the "instance.member/method" syntax.
> - Accept the "this" keyword.
>
> So, I accept any kind of sugerence, (but please don't insult/be rude, as
> people here tend to be, that kind of messages will be ignored).
Javier <·······@gmail.com> writes:
> My first problem comes here from the fact that before writing the code
> that writes members, generics and methods, I must teach the compiler
> reader to read the notation "instance.method/member".
You have three choices to deal with that. The first two are "hard".
The first is to solve it at read time.
There are two ways to do it:
+ install a readtable full of reader macros, for each character, which
gives you the control when the reader reads any character, so you
can implement your scanner and return whatever object you want when
"instance.something" is read, like a (something instance) form.
Advantage: it should be compatible with the existing functions such
as CL:READ, CL:LOAD, etc.
Inconvenients:
- your parser have the insides out, so it's harder to write.
- you will have to carefully install your readtable everywhere
you need it, notably if some source installs its own readtable,
it will disable your scanner.
- you will probably get the transformation even when you don't
want it:
+ implement your own reader, or use a free reader which has hooks
allowing you to interpret tokens as you want.
Advantage: just a simple hook to write.
Inconvenient: CL:READ, CL:LOAD won't use it. If possible, you'd
have to replace all the functions in the
implementation that use the reader.
The second is to solve it at macro expansion time. The idea is that
you will wrap all the instances of instance.something in one of your
macros, and this macro will have to walk the code to be able to
identify where a symbol containing a dot must be substituted with a
message sending form, and where not.
(brain.parse-sentences '(|this is a sentence. this is another one.|
|I.B.M is a company.|))
Advantage: it's simplier than hacking the reader. The places where
your "syntax" is active are also lexically identified with
your macro.
Inconvenient: implementing a (portable) code walker is not much
simplier than hacking the reader.
(In anycase, don't you want to implement chaining syntax:
object.getSubObj.getAnotherObj.doSomething
)
In the third solution you write a "parenthesized" reader macro or
dispatching reader macro, eg. [ ... ], #[ ... ], {}, #{} or #j( ... )
or whatever, and you can implement your own scanner and parser inside
these parentheses.
Advantage: simplier to write, you can implement any grammar you want
(as long as the "parenthesis" you use to wrap it is well
balanced inside.
Inconvenient: It may be harder to mix lisp code with this syntax.
However, you may provide a wrapper inside the wrapper,
like:
(defun m (x)
{ -- reader macro to start strange syntax
x.doSomething( #(if (< 0 {x.number}) 1 (* {x.number} (m {x.number - 1}))) );
if(x.number==1){
x.print("Hello!");
}
return x.result;
})
where {} in lisp code reads strange code, and where # in strange code
reads lisp code. (Since lisp code is always well balanced, you don't
need parentheses here).
But my advice would be, unless you have (paying) users who want a
specific syntax, to forget about this notation.
(do-something object) is much better.
--
__Pascal Bourguignon__
Pascal J. Bourguignon escribi�:
> Javier <·······@gmail.com> writes:
>
>> My first problem comes here from the fact that before writing the code
>> that writes members, generics and methods, I must teach the compiler
>> reader to read the notation "instance.method/member".
>
> You have three choices to deal with that. The first two are "hard".
>
> The first is to solve it at read time.
> There are two ways to do it:
>
> + install a readtable full of reader macros, for each character, which
> gives you the control when the reader reads any character, so you
> can implement your scanner and return whatever object you want when
> "instance.something" is read, like a (something instance) form.
>
> Advantage: it should be compatible with the existing functions such
> as CL:READ, CL:LOAD, etc.
>
> Inconvenients:
>
> - your parser have the insides out, so it's harder to write.
>
> - you will have to carefully install your readtable everywhere
> you need it, notably if some source installs its own readtable,
> it will disable your scanner.
>
> - you will probably get the transformation even when you don't
> want it:
>
>
> + implement your own reader, or use a free reader which has hooks
> allowing you to interpret tokens as you want.
>
> Advantage: just a simple hook to write.
>
> Inconvenient: CL:READ, CL:LOAD won't use it. If possible, you'd
> have to replace all the functions in the
> implementation that use the reader.
>
>
> The second is to solve it at macro expansion time. The idea is that
> you will wrap all the instances of instance.something in one of your
> macros, and this macro will have to walk the code to be able to
> identify where a symbol containing a dot must be substituted with a
> message sending form, and where not.
>
> (brain.parse-sentences '(|this is a sentence. this is another one.|
> |I.B.M is a company.|))
>
> Advantage: it's simplier than hacking the reader. The places where
> your "syntax" is active are also lexically identified with
> your macro.
>
> Inconvenient: implementing a (portable) code walker is not much
> simplier than hacking the reader.
>
>
> (In anycase, don't you want to implement chaining syntax:
> object.getSubObj.getAnotherObj.doSomething
> )
>
>
>
> In the third solution you write a "parenthesized" reader macro or
> dispatching reader macro, eg. [ ... ], #[ ... ], {}, #{} or #j( ... )
> or whatever, and you can implement your own scanner and parser inside
> these parentheses.
>
> Advantage: simplier to write, you can implement any grammar you want
> (as long as the "parenthesis" you use to wrap it is well
> balanced inside.
>
> Inconvenient: It may be harder to mix lisp code with this syntax.
> However, you may provide a wrapper inside the wrapper,
> like:
>
> (defun m (x)
> { -- reader macro to start strange syntax
> x.doSomething( #(if (< 0 {x.number}) 1 (* {x.number} (m {x.number - 1}))) );
> if(x.number==1){
> x.print("Hello!");
> }
> return x.result;
> })
>
> where {} in lisp code reads strange code, and where # in strange code
> reads lisp code. (Since lisp code is always well balanced, you don't
> need parentheses here).
>
>
>
> But my advice would be, unless you have (paying) users who want a
> specific syntax, to forget about this notation.
> (do-something object) is much better.
>
Thank you.
None of your solutions seems to be very good...
I know the existence of set-macro-character, for example:
(set-macro-character #\.
#'(lambda (stream char)
(list 'quote (read stream t nil t))))
That would be a way to define a synonymous for "'".
It just would be nice if there is a way to do the same thing, but
considering words read before and after ".". The problem is that when it
reaches the ".", it already has read what is before it. So in this case
the solution may be, perhaps, the first you said?
If this is too difficult, I may consider too the possibility of
instaling a secondary macro character, for example:
> (.instance.method arg1 arg2)
But it is not very elegant. The ideal would be just "instance.method".
On 12 mar, 12:50, Javier <·······@gmail.com> wrote:
> Pascal J. Bourguignon escribió:
>
>
>
> > Javier <·······@gmail.com> writes:
>
> >> My first problem comes here from the fact that before writing the code
> >> that writes members, generics and methods, I must teach the compiler
> >> reader to read the notation "instance.method/member".
>
> > You have three choices to deal with that. The first two are "hard".
>
> > The first is to solve it at read time.
> > There are two ways to do it:
>
> > + install a readtable full of reader macros, for each character, which
> > gives you the control when the reader reads any character, so you
> > can implement your scanner and return whatever object you want when
> > "instance.something" is read, like a (something instance) form.
>
> > Advantage: it should be compatible with the existing functions such
> > as CL:READ, CL:LOAD, etc.
>
> > Inconvenients:
>
> > - your parser have the insides out, so it's harder to write.
>
> > - you will have to carefully install your readtable everywhere
> > you need it, notably if some source installs its own readtable,
> > it will disable your scanner.
>
> > - you will probably get the transformation even when you don't
> > want it:
>
> > + implement your own reader, or use a free reader which has hooks
> > allowing you to interpret tokens as you want.
>
> > Advantage: just a simple hook to write.
>
> > Inconvenient: CL:READ, CL:LOAD won't use it. If possible, you'd
> > have to replace all the functions in the
> > implementation that use the reader.
>
> > The second is to solve it at macro expansion time. The idea is that
> > you will wrap all the instances of instance.something in one of your
> > macros, and this macro will have to walk the code to be able to
> > identify where a symbol containing a dot must be substituted with a
> > message sending form, and where not.
>
> > (brain.parse-sentences '(|this is a sentence. this is another one.|
> > |I.B.M is a company.|))
>
> > Advantage: it's simplier than hacking the reader. The places where
> > your "syntax" is active are also lexically identified with
> > your macro.
>
> > Inconvenient: implementing a (portable) code walker is not much
> > simplier than hacking the reader.
>
> > (In anycase, don't you want to implement chaining syntax:
> > object.getSubObj.getAnotherObj.doSomething
> > )
>
> > In the third solution you write a "parenthesized" reader macro or
> > dispatching reader macro, eg. [ ... ], #[ ... ], {}, #{} or #j( ... )
> > or whatever, and you can implement your own scanner and parser inside
> > these parentheses.
>
> > Advantage: simplier to write, you can implement any grammar you want
> > (as long as the "parenthesis" you use to wrap it is well
> > balanced inside.
>
> > Inconvenient: It may be harder to mix lisp code with this syntax.
> > However, you may provide a wrapper inside the wrapper,
> > like:
>
> > (defun m (x)
> > { -- reader macro to start strange syntax
> > x.doSomething( #(if (< 0 {x.number}) 1 (* {x.number} (m {x.number - 1}))) );
> > if(x.number==1){
> > x.print("Hello!");
> > }
> > return x.result;
> > })
>
> > where {} in lisp code reads strange code, and where # in strange code
> > reads lisp code. (Since lisp code is always well balanced, you don't
> > need parentheses here).
>
> > But my advice would be, unless you have (paying) users who want a
> > specific syntax, to forget about this notation.
> > (do-something object) is much better.
>
> Thank you.
>
> None of your solutions seems to be very good...
>
> I know the existence of set-macro-character, for example:
>
> (set-macro-character #\.
> #'(lambda (stream char)
> (list 'quote (read stream t nil t))))
>
> That would be a way to define a synonymous for "'".
>
> It just would be nice if there is a way to do the same thing, but
> considering words read before and after ".". The problem is that when it
> reaches the ".", it already has read what is before it. So in this case
> the solution may be, perhaps, the first you said?
Try (unread-char) - it reads characters backwards. You should read
characters backwards until you find either a space, newline or (,
maybe some others.
But be careful, the dot "." is already a standard macro in ANSI Common
Lisp to create, for instance, a improper list or a circular list.
'(1 2 3 4 . 5)
'#1#=(1 2 3 4 . #1#)
gugamilare escribi�:
>> I know the existence of set-macro-character, for example:
>>
>> (set-macro-character #\.
>> #'(lambda (stream char)
>> (list 'quote (read stream t nil t))))
>>
>> That would be a way to define a synonymous for "'".
>>
>> It just would be nice if there is a way to do the same thing, but
>> considering words read before and after ".". The problem is that when it
>> reaches the ".", it already has read what is before it. So in this case
>> the solution may be, perhaps, the first you said?
>
> Try (unread-char) - it reads characters backwards. You should read
> characters backwards until you find either a space, newline or (,
> maybe some others.
> But be careful, the dot "." is already a standard macro in ANSI Common
> Lisp to create, for instance, a improper list or a circular list.
>
> '(1 2 3 4 . 5)
> '#1#=(1 2 3 4 . #1#)
And also for floating point numbers like 1.23 ....
Unfortunately, your solutions seems to do not work, as unread-char only
reads one character backwards, and cannot be called twice, as say the
Hyperspec.
gugamilare <··········@gmail.com> writes:
>> It just would be nice if there is a way to do the same thing, but
>> considering words read before and after ".". The problem is that when it
>> reaches the ".", it already has read what is before it. So in this case
>> the solution may be, perhaps, the first you said?
>
> Try (unread-char) - it reads characters backwards. You should read
> characters backwards until you find either a space, newline or (,
> maybe some others.
No, UNREAD-CHAR can unread only ONE character.
--
__Pascal Bourguignon__
On 12 mar, 15:10, ····@informatimago.com (Pascal J. Bourguignon)
wrote:
> gugamilare <··········@gmail.com> writes:
> >> It just would be nice if there is a way to do the same thing, but
> >> considering words read before and after ".". The problem is that when it
> >> reaches the ".", it already has read what is before it. So in this case
> >> the solution may be, perhaps, the first you said?
>
> > Try (unread-char) - it reads characters backwards. You should read
> > characters backwards until you find either a space, newline or (,
> > maybe some others.
>
> No, UNREAD-CHAR can unread only ONE character.
>
> --
> __Pascal Bourguignon__
Hum, I completely forgot. It looks like your (Javier's) only options
are the ones that Pascal stated.
Anyway, when it is said that CLOS can adapt to your needs, It is not
about changing the Lisp syntax (which is not very nice), but about,
e.g. changing the order on which the methods are called (using MOP,
compute-class-precedence-list and define-method-combination), what is
done with their result (define-method-combination), among many other
things.
Examples: Cells, elephant.
Javier wrote:
> I'd like to implement this:
>
> (defmyclass foo1 :extends foo0
> "This is documentation for foo1 class"
> (:public :static
> memberstatic1 :init 'value)
> (:protected
> member1 :type symbol :init 'member1 :doc "Documentation for member1"
> member2)
> (:public
> method1 :method (((arg1 number) (arg2 number))
> (if (< arg1 arg2)
> this.member1
> this.member2))
> method1 :method (() this.member1)
> :constructor (() nil)
> :constructor (((arg1 symbol))
> (setf this.member2 arg1))))
>
> (defvar *foo* (new foo1 'example-arg))
>
> (print *foo*.member2) ;error, it is protected
>
> (foo1.method1) ;error, foo1 is not an instance
>
> (print foo1.memberstatic1) ; 'value
>
> (print (*foo*.method1 2 3)) ; 'member1
>
>
>
> So I have a similar object system to Java. I want it to be 100%
> compatible with CLOS, so I can interchange classes from one system to
> another. My main problems are:
>
> - Passing different number of arguments to methods while remaining fully
> polymorphic.
You can do this by defining generic functions with all the arguments you
will eventually need, and then defining wrapper functions with mostly
optional parameters that call the underlying generic functions by
passing the passed arguments and filling in the missing ones by
providing default values.
> - The same with constructors.
Same solution.
> - Modify the reader to accept the "instance.member/method" syntax.
The "." has special status in Common Lisp. Message-sending-based
languages have all kinds of different syntax for message sending, so
just pick another one. For example "<-" may be a good choice.
As soon as you agree to this slight variation in design choice, you have
several options:
+ Hack the reader to accept your new syntax. It's probably easiest to
use different parentheses as well, and something like [obj <- arg1 arg2
arg3] should be relatively easy to make work.
+ Turn every object of your object system into funcallable object, and
define <- as a global constant (for example referring to itself). Then
you can say (obj <- arg1 arg2 arg3), and the corresponding "funcallable"
function can just ignore its first argument.
+ Use "<-" in the first position, so say (<- obj arg1 arg2 arg3). That's
the easiest way to go.
+ Turn "<-" into a macro, which can give you the interesting benefit
that you can chain message sends, roughly like this:
(<- obj
(msg1 arg1 arg2 arg3)
(msg2 arg1 arg2)
(msg3 arg1))
...with the idea that all messages are sent to the same object.
+ You have to keep in mind that Java distinguishes between methods and
fields in the syntax for accessing them: It's obj.field, but
obj.method()! So you have to distinguish between function space and
value space in your object system as well (which may hurt in some corner
cases when you go for the reader hack solution).
> - Accept the "this" keyword.
That's trivial, I would use that as one of the very first exercises for
beginners in macro programming.
In general, it's advisable not to fight the very few fixed design
decisions in Common Lisp (like the syntax of ".", "(" and ")") too much,
but just go with the flow. Then you will notice that you have much more
flexibility than in other languages, where almost everything is fixed.
Pascal
--
ELS'09: http://www.european-lisp-symposium.org/
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
Hi!
First problem is that java is statically typed.
You would need to make lisp statically typed too,
otherwise you would lose expressive power, or
efficiency, or both.
> (defvar *foo* (new foo1 'example-arg))
> (print *foo*.member2) ;error, it is protected
Here member2 is dispatched at runtime.
This problem is fundamental. You could try use
something like this to overcome the problem:
http://www.franz.com/support/documentation/current/doc/environments.htm
Some CL implementations have the feature as it
was specified in CLTL2. It was not included into modern
CL standard. I didn't try this but hope this would help.
You would need some implementation-dependent code, but
this is normal for most really useful portable CL projects.
Try to google for ready compatibility layers. Also try to
google for other static type prior art, e.g. nisp.
Don't use leading dot. SBCL ignores readmacros when
reading dot in the middle of the list and it is hard
to work around. Also, beware that you'll get
punished for any elegant readmacros. You would likely
lose definition search and break symbol completion if you
use a.b syntax, or ·@b, or a(#\anything-else)b with readmacro.
So, whatever you want to try, check this first in all of
your target implementations and estimate is it worth doing.
I advice you to name methods as classname-methodname,
classname/methodname or something like this, not as just
"methodname". Thus you could avoid the congruent lambda list
limitation and get rid of unnecessary dynamic dispatching
sometimes. Use something like j-methodname or j:methodname
or @methodname for trampoline method/macro, not just methodname.
Why? If you have "add" method, and use some CLOS library which
has "add" method too, you fall into trouble. It is very likely
that your add method would be from other package that other
library's "add" method and you could never use both that-library
package and your "javaclos" package. This would be a pain for
every derived work (and this looks like another fundamental
disadvantage of CLOS compared to java). If you name your
"javish" trampoline method @add, or j:add, you would make
the conflict less likely and at the same time avoid package
hell.
So I think that j:add is the most scalable solution.
It is far from elegant though...
Well, I wish you good luck, but the task is hard. I was
thinking about doing something similar. But I failed to do
a good design which wouldn't break development environments.
Reasons for that and some ideas I found are listed above.
Maybe I wasn't sufficiently persistent.