Accessing "this" in gen-class constructor

674 views
Skip to first unread message

CuppoJava

unread,
Dec 26, 2008, 5:40:28 PM12/26/08
to Clojure
Hi,
I've hit a stumbling block using Clojure's gen-class facility for
constructors.
Is there anyway to access "this" inside Clojure's constructor/init
function?

ie. The following type of code is quite common in Java. How would you
do the same in Clojure?

public class MyDerivedClass extends SuperClass{ //<-- Derived Class
public MyDerivedClass (){
super("derived class"); //<-- Call superclass constructor
setDescription("this is a derived class"); //<-- Call inherited
method
}
}

Thanks
-Patrick

CuppoJava

unread,
Dec 27, 2008, 12:41:47 AM12/27/08
to Clojure
I found that I can use another factory method to workaround this
limitation. I can first instantialize the object to get a reference,
and then initialize all it's settings. This works only if I don't
expect this class to be derived from. Any subclass would expect the
class to be fully initialized in the constructor, and not have to call
another initialize_settings() function.

Emeka

unread,
Dec 27, 2008, 5:50:05 AM12/27/08
to clo...@googlegroups.com
Can I see you code?

Emeka

CuppoJava

unread,
Dec 27, 2008, 8:05:31 PM12/27/08
to Clojure
Here's my stab at it.
I'm having problems with the setDescription() line.
Thanks for your help
-Patrick

(ns test)
(gen-class
:name test.MyDerivedClass
:extends [SuperClass]
:init init
:constructors {[] [String]})

(defn -init []
;The following line doesn't work.
;I need to call setDescription on this object
;who's reference is not available yet.
(. this setDescription "this is a derived class")

;Superclass constructor
[["derived class"] nil]

Daniel E. Renfer

unread,
Dec 27, 2008, 8:13:16 PM12/27/08
to clo...@googlegroups.com
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

The first parameter to these functions should be the reference the object.

so try:

(defn -init [this]
(.setDescription this "this is a derived class")
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAklW0qAACgkQWorbjR01Cx5qaACgyUEFNoNDlPt6YNNhbCCwI92r
FmEAniT/gtGvnmOjDFZVBKIco8tZ4aDQ
=FtTB
-----END PGP SIGNATURE-----

CuppoJava

unread,
Dec 27, 2008, 9:24:56 PM12/27/08
to Clojure
I believe the first parameter must be "this", only in the case of
methods .
The init function doesn't take a "this" parameter.

Here's an example of my problem, MyDerivedClass is a subclass of
Thread.

This doesn't work, because "this" actually refers to the first
argument passed to the constructor. It does not refer to the object
itself.

(ns test)
(gen-class
:name test.MyDerivedClass
:extends Thread
:init init)

(defn -init [this]
;The following line doesn't work.
;I need to call setName on this object
;who's reference is not available yet.
(println this)
(. this setName "my derived class")

;Superclass constructor
[[] nil])

Chouser

unread,
Dec 29, 2008, 3:40:21 PM12/29/08
to clo...@googlegroups.com
On Sat, Dec 27, 2008 at 9:24 PM, CuppoJava <patrick...@hotmail.com> wrote:
>
> I believe the first parameter must be "this", only in the case of
> methods .
> The init function doesn't take a "this" parameter.

Correct.

My understanding is that the init function is actually run before the
instance is even created. So no only is there no "this" parameter,
there's not even a "this" value yet.

Instead, your init function returns values to pass to the superclass
constructor and the value to use as your object's state. Also note
that I had to specify :constructors in order for my init to accept no
args but to use the constructor of the superclass that takes a String.

(ns net.n01se.MyThread
(:gen-class
:extends "java.lang.Thread"
:constructors {[] [String]}
:init my-init
:state myState
:exposes-methods {getId getIdSuper}))

(defn -my-init []
(prn :init-my-thread)
[["my derived class"] "this is my state"])

(defn -getId [this]
(+ 123000 (.getIdSuper this)))

This also demonstrates the use of :exposes-methods to call the
superclass's implementation of a method I'm overridding.

Note that because I didn't use a mutable object for myState, (instead
using the string "this is my state"), there's no way to change the
value of myState.

user=> (compile 'net.n01se.MyThread)
net.n01se.MyThread
user=> (def x (net.n01se.MyThread.))
:init-my-thread
#'user/x
user=> (.myState x)
"this is my state"
user=> (.getId x)
123008
user=> (.getName x)
"my derived class"

--Chouser

CuppoJava

unread,
Dec 29, 2008, 8:02:25 PM12/29/08
to Clojure
Thanks for the reply Chouser,

Yeah, I figured it would be like that. No "this" value actually exists
until after the init function is called.

The reason I'm asking about this is that it's quite standard practice
to set up some parameters inside the constructor of a class.

ie. A use-case like this is quite common, and (I think) reasonable.

public class MyThread extends Thread{
public MyThread(){
setName("This is my thread");
}
}

So whenever the user creates an instance of MyThread, he can be
guaranteed that the thread's name has already been appropriately set.

How would you do this in Clojure?

Chouser

unread,
Dec 29, 2008, 8:14:55 PM12/29/08
to clo...@googlegroups.com
On Mon, Dec 29, 2008 at 8:02 PM, CuppoJava <patrick...@hotmail.com> wrote:
>
> The reason I'm asking about this is that it's quite standard practice
> to set up some parameters inside the constructor of a class.
>
> ie. A use-case like this is quite common, and (I think) reasonable.
>
> public class MyThread extends Thread{
> public MyThread(){
> setName("This is my thread");
> }
> }
>
> So whenever the user creates an instance of MyThread, he can be
> guaranteed that the thread's name has already been appropriately set.
>
> How would you do this in Clojure?

The example I posted does exactly this -- the name of all MyThreads
start as "my derived class" as demonstrated by:

CuppoJava

unread,
Dec 30, 2008, 11:52:50 AM12/30/08
to Clojure
Ah sorry I missed that.

However, you accomplished this only because there exists a constructor
in Thread that takes a String name argument.
As a general case, it's not usually that convenient...

ie.

public class MyThread extends Thread{
public MyThread(){
setName("This is my thread");
setPropertyA("bla bla bla");
setPropertyB("bla bla bla");
etc...
}

}

Chouser

unread,
Dec 30, 2008, 12:10:42 PM12/30/08
to clo...@googlegroups.com

Seems like that class has a rather unfortunate API. :-)

As far as I know, this is not currently possible with gen-class.
Seems like you'd need some kind of post-constructor hook, provided
just to deal with mutable state of the base class.

I wonder if Rich would accept a patch providing an :after-ctor option
to gen-class.

--Chouser

CuppoJava

unread,
Dec 30, 2008, 1:24:42 PM12/30/08
to Clojure
Haha yeah... it's a rather poor API.

I'm making do with a temporary post-constructor hook that I manually
call after instantiating the object right now. But it's tedious and
error-prone.

Thanks for the help Chouser

Chouser

unread,
Jan 15, 2009, 10:46:57 AM1/15/09
to clo...@googlegroups.com
On Tue, Dec 30, 2008 at 1:24 PM, CuppoJava <patrick...@hotmail.com> wrote:
>
> Haha yeah... it's a rather poor API.
>
> I'm making do with a temporary post-constructor hook that I manually
> call after instantiating the object right now. But it's tedious and
> error-prone.

I've posted a feature request:
http://code.google.com/p/clojure/issues/detail?id=45

Now you can submit your CA, submit a patch, and nobody will ever have
to suffer your pain again. :-)

--Chouser

Reply all
Reply to author
Forward
0 new messages