Symbols evaluated at compile time?

61 views
Skip to first unread message

Elena

unread,
Mar 16, 2009, 6:35:49 AM3/16/09
to Clojure
Hi,

in this code:

(defn main []
(check-services))

(defn check-services []
1)

if I call slime-eval-defun on "main" before calling it on "check-
services", Clojure aborts with:

java.lang.Exception: Unable to resolve symbol: check-services in this
context (NO_SOURCE_FILE:3)
[Thrown class clojure.lang.Compiler$CompilerException]

Is it expected?


Christophe Grand

unread,
Mar 16, 2009, 6:40:34 AM3/16/09
to clo...@googlegroups.com
Elena a écrit :

Yes, it prevents typos to go unnoticed. You can write a forward
declaration :

(declare check-services); equivalent to (def check-services)

(defn main []
(check-services))

(defn check-services []
1)


HTH

Christophe

--
Professional: http://cgrand.net/ (fr)
On Clojure: http://clj-me.blogspot.com/ (en)


Konrad Hinsen

unread,
Mar 16, 2009, 6:43:33 AM3/16/09
to clo...@googlegroups.com

Yes. Clojure checks that symbols are defined before they are used.
You can put

(declare check-services)

before your definition of main to define the symbol and make it clear
to the (human) reader that you indeed to give the real definition later.

Konrad.

Elena

unread,
Mar 16, 2009, 6:49:07 AM3/16/09
to Clojure


On Mar 16, 10:40 am, Christophe Grand <christo...@cgrand.net> wrote:

>
> Yes, it prevents typos to go unnoticed. You can write a forward
> declaration :
>
> (declare check-services); equivalent to (def check-services)
>
> (defn main []
>         (check-services))
>
> (defn check-services []
>         1)
>

OK, thanks. I was expecting a behavior similar to Scheme (and maybe
Common Lisp).

Doesn't that hampers interactive development? I mean: you have to
develop the program in a more controlled manner.

Elena

unread,
Mar 16, 2009, 1:36:48 PM3/16/09
to Clojure
On Mar 16, 10:43 am, Konrad Hinsen <konrad.hin...@laposte.net> wrote:

> Yes. Clojure checks that symbols are defined before they are used.  
> You can put
>
> (declare check-services)
>
> before your definition of main to define the symbol and make it clear  
> to the (human) reader that you indeed to give the real definition later.

IMHO, this is a no-no for interactive development. I understand that
it helps avoiding undefined symbols, but such code integrity checks
could be delayed to a final compilation stage. Having them earlier
forces you to develop code in a bottom-up way.

Meikel Brandmeyer

unread,
Mar 16, 2009, 2:58:03 PM3/16/09
to clo...@googlegroups.com
Hi,

Am 16.03.2009 um 18:36 schrieb Elena:

> IMHO, this is a no-no for interactive development. I understand that
> it helps avoiding undefined symbols, but such code integrity checks
> could be delayed to a final compilation stage. Having them earlier
> forces you to develop code in a bottom-up way.

I don't think so. I start with a function. *hackhackhack*
Then I realise, that some part should be extracted into
a helper function, eg. to share code with third function.

Then it is matter of convention of the local project, whether
this helper function is place in front or after the other functions
combined with a declare.

I use a top-down approach all the time and it works
pretty well in Clojure.

Sincerely
Meikel

Jeffrey Straszheim

unread,
Mar 16, 2009, 3:14:53 PM3/16/09
to clo...@googlegroups.com
I agree.  It doesn't matter what order the compiler reads the definitions: I can scroll up and type.

It does effect humans reading the code, however.  Often when looking at unfamiliar Clojure code, I find myself scrolling to the bottom first.

Elena

unread,
Mar 16, 2009, 3:32:48 PM3/16/09
to Clojure
On 16 Mar, 20:14, Jeffrey Straszheim <straszheimjeff...@gmail.com>
wrote:

> It does effect humans reading the code, however.  Often when looking at
> unfamiliar Clojure code, I find myself scrolling to the bottom first.

That's exactly my point: why should I scroll to the bottom? That's not
the way I read a written page or report. Can you imagine a report
which starts with the details instead of the more general picture? I
think sometimes we warp ourselves to compensate for our tools
deficiencies, whilst it should be the other way around. It is much
easier for the compiler/interpreter to look ahead, isn't it?

David Nolen

unread,
Mar 16, 2009, 3:45:53 PM3/16/09
to clo...@googlegroups.com
This has come up before. You can actually work around this (search the mailing list for declare) 

I think that when not hacking against the REPL that the default behavior is a good one. Having to use declare bugged me a little at first, but I now consider it a very minor annoyance compared to the advantages I get from programming interactively with Clojure.

Should the REPL have an "interactive" mode where it won't fire an exception on undefined symbols and instead issue compiler warnings? If compiler warnings were issued this would be a nice hook for Emacs and other IDEs.

David

Laurent PETIT

unread,
Mar 16, 2009, 3:58:20 PM3/16/09
to clo...@googlegroups.com
I also agree that I keep going first to the end of the file, searching the real function to launch or to reuse when reading new clojure code ...

What I would be happy with is a way to have clojure not complain before the end of a "unit of compiled code".

For the REPL, that would be somewhat similar to the current behavior : wait before the end of the expression to complain for undefined symbols.

For files, that would be "wait until the end of the file before complaining for undefined symbols, and let me arrange the defs in any order I feel most readable without having to think about placing those (declare) calls".

Now, I don't know if this is something easily feasible in the implementation ...

--
Laurent


2009/3/16 Elena <egar...@gmail.com>

Paul Stadig

unread,
Mar 16, 2009, 4:08:38 PM3/16/09
to clo...@googlegroups.com
I may be missing something, but how does having to (declare) vars fix typos? I don't think anyone is suggesting *creating* a var that is referenced before it is defined. What people are asking for is that the compiler looks-ahead to verify that the var will eventually be defined, and then go on its merry way. Typos would still be discovered, and people wouldn't have to stop and (declare).

I'm not saying it's an easy change...


Paul

David Nolen

unread,
Mar 16, 2009, 4:18:37 PM3/16/09
to clo...@googlegroups.com
On Mon, Mar 16, 2009 at 4:08 PM, Paul Stadig <pa...@stadig.name> wrote:
I may be missing something, but how does having to (declare) vars fix typos? I don't think anyone is suggesting *creating* a var that is referenced before it is defined. What people are asking for is that the compiler looks-ahead to verify that the var will eventually be defined, and then go on its merry way. Typos would still be discovered, and people wouldn't have to stop and (declare).

Yeah I wasn't suggesting that vars should be created, sorry if it sounded like I was (I mentioned declare because this came up in another thread about declare and someone had hacked the reader to not bail immediately on undefined symbols).  

In CL, if you have definitions out of order in the compiler will issue warnings.

Elena

unread,
Mar 16, 2009, 4:22:00 PM3/16/09
to Clojure
On 16 Mar, 20:45, David Nolen <dnolen.li...@gmail.com> wrote:
> This has come up before. You can actually work around this (search the
> mailing list for declare)

I've searched the mailing list and I've found also an explanation by
Rich Hickey (I apologize for not having done it in the first instance)
for such a design decision. I agree that allowing undefined symbols
would lead to runtime errors. I'm only complaining about applying such
sanity checks in the REPL, when I'm drawing a sketch.

> Should the REPL have an "interactive" mode where it won't fire an exception
> on undefined symbols and instead issue compiler warnings? If compiler
> warnings were issued this would be a nice hook for Emacs and other IDEs.

I think that would be ideal: if you intended to leave a symbol
undefined, that warning would come expected, otherwise you'd know you
had just made a typo.

Elena

unread,
Mar 16, 2009, 4:26:19 PM3/16/09
to Clojure
On 16 Mar, 20:58, Laurent PETIT <laurent.pe...@gmail.com> wrote:

> For files, that would be "wait until the end of the file before complaining
> for undefined symbols, and let me arrange the defs in any order I feel most
> readable without having to think about placing those (declare) calls".

I second your proposal.

Paul Stadig

unread,
Mar 16, 2009, 4:36:31 PM3/16/09
to clo...@googlegroups.com
On Mon, Mar 16, 2009 at 4:18 PM, David Nolen <dnolen...@gmail.com> wrote:
On Mon, Mar 16, 2009 at 4:08 PM, Paul Stadig <pa...@stadig.name> wrote:
I may be missing something, but how does having to (declare) vars fix typos? I don't think anyone is suggesting *creating* a var that is referenced before it is defined. What people are asking for is that the compiler looks-ahead to verify that the var will eventually be defined, and then go on its merry way. Typos would still be discovered, and people wouldn't have to stop and (declare).

Yeah I wasn't suggesting that vars should be created, sorry if it sounded like I was (I mentioned declare because this came up in another thread about declare and someone had hacked the reader to not bail immediately on undefined symbols).  

Sorry, my fault. I was just responding in general, not to you specifically.
 

In CL, if you have definitions out of order in the compiler will issue warnings.
 

I'm not saying it's an easy change...


Paul


Could someone post the link to the previous discussion? I searched the group for declare, but didn't turn up anything.


Paul

Christian Vest Hansen

unread,
Mar 16, 2009, 4:37:43 PM3/16/09
to clo...@googlegroups.com
Otherwise, for the purpose of bringing a counter argument, I find that
functions naturally group together by their level of abstraction, with
the lowest level of abstraction at the top and the highest at the
bottom.

Considering this, I will boldly claim it usually is not that difficult
to put these groups in their own lib. We could, perhaps, consider it a
sign (for avoiding the word "smell") that a new lib should be defined?
Then, as now, we can let "declare" handle the cases where this isn't
true.

> >
>



--
Venlig hilsen / Kind regards,
Christian Vest Hansen.

David Nolen

unread,
Mar 16, 2009, 4:54:37 PM3/16/09
to clo...@googlegroups.com
Here's the post by Timothy talking about patching the compiler:

http://groups.google.com/group/clojure/msg/ef5bae605f4a0730

Laurent PETIT

unread,
Mar 16, 2009, 4:57:06 PM3/16/09
to clo...@googlegroups.com
Hello Christian,

2009/3/16 Christian Vest Hansen <karma...@gmail.com>

I agree that it's not difficult. But, at least in my own experience, it's not the second step to cleaning up my programs.

I generally try to get code that works, even if in a not really good looking shape. Then I refactor if it is really ugly-looking, or when I see the possibility to factorize between several functions.

So I end up with more general functions, but still, I'm not sure if they deserve their own lib. And maybe they're just general enough for the purpose of the functions of my current file.

It's in a third time, when I want to share code between several namespaces, that libraries in their own namespace show up.

So I think there's room for what I suggested, because the step to seperate functions into libs by a criteria of level of abstraction does not appear that fast in my programming cycle.
 

Elena

unread,
Mar 16, 2009, 5:19:43 PM3/16/09
to Clojure


On 16 Mar, 21:57, Laurent PETIT <laurent.pe...@gmail.com> wrote:
>
> I agree that it's not difficult. But, at least in my own experience, it's
> not the second step to cleaning up my programs.
>
> I generally try to get code that works, even if in a not really good looking
> shape. Then I refactor if it is really ugly-looking, or when I see the
> possibility to factorize between several functions.
>
> So I end up with more general functions, but still, I'm not sure if they
> deserve their own lib. And maybe they're just general enough for the purpose
> of the functions of my current file.
>
> It's in a third time, when I want to share code between several namespaces,
> that libraries in their own namespace show up.
>
> So I think there's room for what I suggested, because the step to seperate
> functions into libs by a criteria of level of abstraction does not appear
> that fast in my programming cycle.

You have just described my way of churning out code for fast
prototypes and ad-hoc programs. Abstractions and cleaning up come
later, once I've understood the task at hand better.

Laurent PETIT

unread,
Mar 16, 2009, 5:31:06 PM3/16/09
to clo...@googlegroups.com
2009/3/16 Elena <egar...@gmail.com>

Exactly. And nowdays, I often realize it's not just "understanding the task at hand" that makes me follow this "unformal process", but also the need/time to first become familiar with the third party lib/framework I'm willing to involve. And generally, those libs/frameworks are hard to grasp at first (at least if I want to not have just "read code" in a day of coding), so I think this notion of "understanding the task at hand" can be generalized not only to the task of "understanding my problem domain", but also to "understanding how to use the libs/frameworks that promise me a clean way of solving my problem domain" :-).


 




André Thieme

unread,
Mar 16, 2009, 5:31:54 PM3/16/09
to Clojure
Didn't you write only yesterday that you want to buy Lispworks?
Speaking about it:
When you define a gui (either manually or by using the builder),
and then you want to add callbacks, you can not just say:
:callback #'my-function and then later in that file actually
implement my-function. It will complain that the definition is not
yet known. So, at least in some cases this is also not possible
in CL.
Only today I found myself typing (decla...) in Lispworks, as I
was thinking in Clojure.

The behaviour of Clojure can be seen as a disadvantage, yes, because
you either need these forward declarations, or you need to arrange
functions different.
But it also protects you from typos. And this can be even more
important. Imagine you have a complex program and accidently
made a typo, and this will go unnoticed for days and days, until
the program actually runs your code...

Meikel Brandmeyer

unread,
Mar 16, 2009, 5:38:09 PM3/16/09
to clo...@googlegroups.com
Hi,

Sometimes, I don't understand you guys. You claim that you have
to develop bottom-up, when in fact you do top-down. I really don't
see the problem with the current behaviour...

Sincerely
Meikel

Laurent PETIT

unread,
Mar 16, 2009, 5:39:49 PM3/16/09
to clo...@googlegroups.com


2009/3/16 André Thieme <splend...@googlemail.com>

Hello André,

Have you read my suggestion of keeping the fact to throw an exception on undefined symbols, but deferring the conclusion until the end of the currently compiled/loaded "unit of code" (a single expression in the REPL, a whole file in a compilation step ...) ?
I'd be interesting to understand what drawbacks this suggestion, if even realized, would have ?
 



Phil Hagelberg

unread,
Mar 16, 2009, 5:41:32 PM3/16/09
to clo...@googlegroups.com
André Thieme <splend...@googlemail.com> writes:

> But it also protects you from typos. And this can be even more
> important. Imagine you have a complex program and accidently
> made a typo, and this will go unnoticed for days and days, until
> the program actually runs your code...

If you go days and days without actually running your code, then you
deserve what you get. A test suite would catch this for you every time;
developing without one is irresponsible.

-Phil

Laurent PETIT

unread,
Mar 16, 2009, 5:44:50 PM3/16/09
to clo...@googlegroups.com


2009/3/16 Meikel Brandmeyer <m...@kotka.de>

Hello Meikel,

In french, we have a sentence for that, that would translate literally into "eat the banana by both ends at the same time".

I don't think top-down and bottom-up programming are antogonists. I often do both at the same time myself.
 


Sincerely
Meikel




Raoul Duke

unread,
Mar 16, 2009, 5:44:44 PM3/16/09
to clo...@googlegroups.com
> If you go days and days without actually running your code, then you
> deserve what you get. A test suite would catch this for you every time;
> developing without one is irresponsible.

geeze people, i'm tired of the "tests are the answer to everything."
give it a break. not every test suite will be perfect from day one,
and what i wrong with defense in depth?

said by a person who likes statically typed, inferred, languages. :-)

Meikel Brandmeyer

unread,
Mar 16, 2009, 5:55:51 PM3/16/09
to clo...@googlegroups.com
Hi,

Am 16.03.2009 um 22:44 schrieb Laurent PETIT:

> In french, we have a sentence for that, that would translate
> literally into "eat the banana by both ends at the same time".
>
> I don't think top-down and bottom-up programming are antogonists. I
> often do both at the same time myself.

According to Paul Graham, this is a one aspect of Lisp:
working both ways at the same time. Top-down for the
program logic and bottom-up by building small helpers
and macros.

My remark was pointed at the fact, that before it was
claimed, that the one way doesn't work in Clojure and
one has to go the other. And then the same person
goes on to contradict him(or her?)self. But be it...

To say something more constructive for the discussion:
here Rich's original answer on the matter:

http://groups.google.com/group/clojure/browse_frm/thread/c3418875208d89e1/0f5b80483329c151?lnk=gst&q=declare+rich+hickey#0f5b80483329c151

Sincerely
Meikel

Laurent PETIT

unread,
Mar 16, 2009, 6:03:27 PM3/16/09
to clo...@googlegroups.com


2009/3/16 Phil Hagelberg <ph...@hagelb.org>

OK, so now is time for another ugly english translation of a french proverb "before saying something, roll your tongue 8 times in your mouth before speaking". I guess this could also be applied for e-mail :-)

Seriously, treating a very large audience of people as "irresponsible" (including Rich himself, the author of clojure) does not seem a very "responsible" behavior, does it ? :-)

In fact, I'm ok when you say that ".... deserve what you get". But please, think about it twice before saying people are irresponsible. Unit tests are not the only answer to bug-free and quality programs.
Quality and correctness is a discipline in its own right, including tests (unit tests, integration tests, functional tests, performance tests, ...), reviews (code review, peer review, architecture review, ...).
Not to say that a lot of bugs are not in the code, but in the specifications (be they formal as in watefall processes, or informal as in agile processes), ..., ....

And please note that when talking about tests, I did not tell if they had to be automatic or not. I think that it's not a natural conclusion to say that tests must be automated.
To me, it's rather a cost/benefits balance that must leads to the conclusion that automatic unit tests are good or not for your project.

My answer had not the intent to offense you, but I couldn't let you write that without reaction, because I'm myself very interested in automatic unit tests, and I think that such intransigent thoughts deserve the cause.

Regards,

--
Laurent
 


-Phil





Elena

unread,
Mar 16, 2009, 6:08:12 PM3/16/09
to Clojure
On 16 Mar, 22:31, André Thieme <splendidl...@googlemail.com> wrote:
> The behaviour of Clojure can be seen as a disadvantage, yes, because
> you either need these forward declarations, or you need to arrange
> functions different.
> But it also protects you from typos. And this can be even more
> important. Imagine you have a complex program and accidently
> made a typo, and this will go unnoticed for days and days, until
> the program actually runs your code...

I agree that such checks are very useful, but:
- why should you wrestle with them also when you are just sketching
out some code at the REPL? Much of the code you are writing is going
to be trashed, so why should you bother keeping up with declarations
dependencies?
- why, when you finally save the source file as a module and and
compile it, the compiler should not be smart enough to read every
definition until the end of the file before complaining?

Your needs change when you are sketching a prototype versus when you
are finalizing the project. Don't you agree?

André Thieme

unread,
Mar 16, 2009, 6:16:05 PM3/16/09
to Clojure
On 16 Mrz., 20:45, David Nolen <dnolen.li...@gmail.com> wrote:

> Should the REPL have an "interactive" mode where it won't fire an exception
> on undefined symbols and instead issue compiler warnings? If compiler
> warnings were issued this would be a nice hook for Emacs and other IDEs.

Yes, I was thinking about this also for a while.
What I propose is:
Whenever Clojure finds the use of a not known symbol in a code file,
it will always look ahead and see if it can find this symbol. If that
is not the case an error should be thrown, as it currently happens.
If it can find the concrete definition it should emit a warning.
The way to silence the warning is to declare that symbol before.

This behaviour would not disturb anyone who likes the current system.
Typos will not go unnoticed, the dev will see that warning.
He/She can add the declare as usual.
Others can continue from that point and have to live with that
warning,
but enjoy the protection from a class of typos and also be able to
arrange their code in a different way and spare these declares.

Timothy Pratley

unread,
Mar 16, 2009, 6:26:19 PM3/16/09
to Clojure
Just FYI,

The actual patch is in the files section:
http://groups.google.com/group/clojure/web/auto-def.patch
With an example:
http://groups.google.com/group/clojure/web/lit-wc.clj
From a longer thread about 'snake' which talked about literate
programming:
http://groups.google.com/group/clojure/browse_thread/thread/2a23a95bf22938a3

It does not implement existence checking upon completion of compile
unit. How exactly should this work? We can keep a set of symbols auto-
defined and 'at checkpoint' test if they are still undefined...
however what is the 'checkpoint'? For fully compiled code the
'checkpoint' is clear - but Clojure is dynamic... what should happen
with this code:

(defn myfun []
(another-fun 5))
(myfun)
(defn another-fun [x]
(inc x))

In a compiled language that would be valid, but in a dynamic language
it is a runtime error. I don't see how to overcome this, which makes
auto-def quite useless :) It seems you either need to accept top-down
or accept undefined symbol runtime errors. There is a third
alternative, which is to use Knuth's literate programming technique of
actually writing your code in TeX and have it transformed from there
to either code or documentation... but again for interactive
development that is quite rigorous.


Regards,
Tim.



On Mar 17, 7:54 am, David Nolen <dnolen.li...@gmail.com> wrote:
> Here's the post by Timothy talking about patching the compiler:
>
> http://groups.google.com/group/clojure/msg/ef5bae605f4a0730
>
> On Mon, Mar 16, 2009 at 4:36 PM, Paul Stadig <p...@stadig.name> wrote:
> > On Mon, Mar 16, 2009 at 4:18 PM, David Nolen <dnolen.li...@gmail.com>wrote:

Phil Hagelberg

unread,
Mar 16, 2009, 6:37:57 PM3/16/09
to clo...@googlegroups.com
Laurent PETIT <lauren...@gmail.com> writes:

> OK, so now is time for another ugly english translation of a french
> proverb "before saying something, roll your tongue 8 times in your
> mouth before speaking". I guess this could also be applied for e-mail

Agreed, it could have been worded better.

But keep in mind the context: it was suggested that certain problems
would go unnoticed for days because the code was loaded never run. I
think this is not a concern; you might as well say these problems could
go unnoticed because the code is never loaded.

> Seriously, treating a very large audience of people as "irresponsible"
> (including Rich himself, the author of clojure) does not seem a very
> "responsible" behavior, does it ? :-)

Clojure has a test suite. It lives in contrib. Bugs in Clojure have been
committed even though they were entirely avoidable, simply because the
test suite wasn't being used. This strikes me as an irresponsible
development practice. It's not horrible, but it wastes peoples' time.

> But please, think about it twice before saying people are
> irresponsible. Unit tests are not the only answer to bug-free and
> quality programs.

Sure, I don't mean that this reflects on peoples' character. I only wish
to judge the practice, not the practitioner.

But for things like clojure, the alternative is to perform those same
tests manually. I don't think it's a good use of humans' time to perform
tasks that could be easily done by a machine.

> And please note that when talking about tests, I did not tell if they
> had to be automatic or not. I think that it's not a natural conclusion
> to say that tests must be automated. To me, it's rather a
> cost/benefits balance that must leads to the conclusion that automatic
> unit tests are good or not for your project.

That's true; certain types of programs (particularly GUIs and JS-heavy
cross-browser web applications) are extremely difficult to automate
tests for. But this is the exception rather than the rule.

-Phil

Elena

unread,
Mar 16, 2009, 6:39:25 PM3/16/09
to Clojure
On 16 Mar, 22:55, Meikel Brandmeyer <m...@kotka.de> wrote:
> My remark was pointed at the fact, that before it was
> claimed, that the one way doesn't work in Clojure and
> one has to go the other. And then the same person
> goes on to contradict him(or her?)self. But be it...
>
> To say something more constructive for the discussion:
> here Rich's original answer on the matter:
>
> http://groups.google.com/group/clojure/browse_frm/thread/c3418875208d...

I bet it's me the "him(or her?)self" :-)

I had already read Rich's opinion, after searching about old threads
about the subject. I think he made a very reasonable decision, but he
was talking about production code. What we are discussing here is the
usefulness of such constraints when just playing at the REPL, a very
different environment. Among the many answers, a (IMHO) reasonable
solution has been proposed, which I repeat here:

- the REPL could allow for an option to just warn about missing
definitions;
- when loading/compiling a file, Clojure could parse all definitions
before complaining about missing ones.

It seems that such a solution would offer both maximum flexibility
when prototyping and maximum sanity checking when finalizing the code.
What do you think?

Laurent PETIT

unread,
Mar 16, 2009, 6:47:47 PM3/16/09
to clo...@googlegroups.com


2009/3/16 Phil Hagelberg <ph...@hagelb.org>


Laurent PETIT <lauren...@gmail.com> writes:

> But please, think about it twice before saying people are
> irresponsible. Unit tests are not the only answer to bug-free and
> quality programs.

Sure, I don't mean that this reflects on peoples' character. I only wish
to judge the practice, not the practitioner.

You're right, I took a judgement on a behaviour for a judgement on persons, sorry for that.

I hope you didn't find my own answer too rude,

Regards,

--
Laurent


Elena

unread,
Mar 16, 2009, 6:47:59 PM3/16/09
to Clojure
On 16 Mar, 23:26, Timothy Pratley <timothyprat...@gmail.com> wrote:
> For fully compiled code the
> 'checkpoint' is clear - but Clojure is dynamic... what should happen
> with this code:
>
> (defn myfun []
>   (another-fun 5))
> (myfun)
> (defn another-fun [x]
>   (inc x))
>
> In a compiled language that would be valid, but in a dynamic language
> it is a runtime error. I don't see how to overcome this, which makes
> auto-def quite useless :)

I think this should be a runtime error. What we are discussing here is
in:

(defn myfun []
(another-fun 5))

(defn another-fun [x]
(inc x))

"myfun" definition is rejected, even if "another-fun" is just few
lines away.

Phil Hagelberg

unread,
Mar 16, 2009, 6:59:15 PM3/16/09
to clo...@googlegroups.com
Laurent PETIT <lauren...@gmail.com> writes:

Not at all. The latter is far more common, especially in online discussions.

And to say that people deserve the problems that come upon them, that
was harsh of me. I rather should have said that they should expect to
have problems like that.

-Phil

Elena

unread,
Mar 16, 2009, 6:59:47 PM3/16/09
to Clojure
Furthermore, if I understand Rich's opinion in that regards, this
code:

(defn myfun []
(another-fun 5))

should be rejected if definition of "another-fun" is missing (but I'd
say: only in code to be released).

Meikel Brandmeyer

unread,
Mar 16, 2009, 7:02:56 PM3/16/09
to clo...@googlegroups.com
Hi,

Am 16.03.2009 um 23:39 schrieb Elena:

> - the REPL could allow for an option to just warn about missing
> definitions;
> - when loading/compiling a file, Clojure could parse all definitions
> before complaining about missing ones.
>
> It seems that such a solution would offer both maximum flexibility
> when prototyping and maximum sanity checking when finalizing the code.
> What do you think?

I probably wouldn't notice such a change. I code in
the repl only very small snippets. To check my
expectations of some return value of a function or
the like. (Basically poor man's debugger)

Things like a function I write in a file and send them
to the clojure server, and only call them in the repl.

I almost never write a function like this.

(defn foo [] (let [x (bar)] (inc x)))

"Hmmm... So how might bar look like?"

It's almost always the other way around:

(defn foo [] (let [x (long ugly stuff)] (inc x)))

"Iek. I should refactor this."

Hmm... So maybe I don't do prototyping....

Sincerely
Meikel

Laurent PETIT

unread,
Mar 16, 2009, 7:14:05 PM3/16/09
to clo...@googlegroups.com
Hello Tim,

2009/3/16 Timothy Pratley <timothy...@gmail.com>


Just FYI,

The actual patch is in the files section:
http://groups.google.com/group/clojure/web/auto-def.patch
With an example:
http://groups.google.com/group/clojure/web/lit-wc.clj
From a longer thread about 'snake' which talked about literate
programming:
http://groups.google.com/group/clojure/browse_thread/thread/2a23a95bf22938a3

It does not implement existence checking upon completion of compile
unit. How exactly should this work? We can keep a set of symbols auto-
defined and 'at checkpoint' test if they are still undefined...
however what is the 'checkpoint'? For fully compiled code the
'checkpoint' is clear - but Clojure is dynamic... what should happen
with this code:

Yes, I think the checkpoint should be at the end of the Compiler.load(Reader rdr, String sourcePath, String sourceName) method call.


(defn myfun []
 (another-fun 5))
(myfun)
(defn another-fun [x]
 (inc x))

In a compiled language that would be valid, but in a dynamic language
it is a runtime error.

I personally have no problem with that being a runtime error. Indeed, I tend to write functions for everything, not even for bootstraping a ns (bootstrapping a ns at the end of a file does not appeal to me *at all *).


 
I don't see how to overcome this, which makes
auto-def quite useless :)

Not at all, I think. It's just "full" auto-def that is certainly too lazy. "scoped"-autodef does not suffer from the same problem, even, I think, for production code (or please, someone, give me some examples where it could let bugs pass through).
 

Laurent PETIT

unread,
Mar 16, 2009, 7:35:56 PM3/16/09
to clo...@googlegroups.com
Tim,

I see in clojure a var named ALLOW_UNRESOLVED_VARS.

Could you explain me how it works compared to the new AUTO_DEF that is introduced ?

I think there's a subtlety between resolved var / defined var that I don't understand right now ...

Thanks,

--
Laurent

2009/3/16 Timothy Pratley <timothy...@gmail.com>

Stephen C. Gilardi

unread,
Mar 16, 2009, 8:15:36 PM3/16/09
to clo...@googlegroups.com

On Mar 16, 2009, at 6:59 PM, Elena wrote:

> Furthermore, if I understand Rich's opinion in that regards, this
> code:
>
> (defn myfun []
> (another-fun 5))
>
> should be rejected if definition of "another-fun" is missing (but I'd
> say: only in code to be released).

I don't mind the current behavior of requiring a var to be def'd
before it's referenced. I do find the idea of relaxing that
requirement interesting, though, so I thought about one possible way
to accomplish it.

To support auto-defining of unresolved symbols, either at the repl or
in loaded files, Clojure could provide a var:

*autodef-unresolved-symbols*

When true, any symbol references that would have triggered the "unable
to resolve symbol" exception would instead be auto-def'd as unbound
and resolved. (Note that since they would be unbound, they still could
not be dereferenced which is cool.)

The repl could allow this to be set!-able.

If *autodef-unresolved-symbols* is true, and if "a" has never been
mentioned before, this interaction with Clojure:

user=> a
java.lang.Exception: Unable to resolve symbol: a in this context

would become:

user=> a
java.lang.IllegalStateException: Var user/a is unbound.

When a symbol is auto-def'd (presumably in ns-resolve, or in the Java
code that supports it), the corresponding resolved symbol would be
added to an internal ref (bound to a set):

*autodefs*

One could retrieve the names of any (currently/still) unbound
autodef'd vars via a call:

(unbound-autodefs)

This call would first update the value bound to the ref *autodefs* by
removing any of its entries that now have root bindings and return its
value after the update. In this way, updating the set of unbound
autodefs is lazy and not done until someone is interested.

For the case of loading files, load could be wrapped with something
like:

(binding [*autodef-unresolved-symbols* true *autodefs* (ref #{})]
(load...)
(when-let unbound (seq (unbound-autodefs))
(throw Exception. (str "The following vars were not defined: "
unbound))))

Under this system:

- the behavior is optional at the repl. anybody not using it sees no
change in behavior there
- Clojure would relax its ordering requirements in source files while
still ensuring that all forward references are satisfied by the end of
each file.
- any vars that are intended to be unbound would (still) have to be
def'd explicitly.

This system seems workable and desirable to me, but I gather that
Common Lisp packages have some subtle and sometimes undesirable
behaviors associated with a similar capability. I don't know whether
other Clojure goodness would make any such issues unimportant in
practice or if they would still be a problem.

--Steve

André Thieme

unread,
Mar 16, 2009, 8:22:06 PM3/16/09
to Clojure
On 16 Mrz., 22:41, Phil Hagelberg <p...@hagelb.org> wrote:
Phil, it is not me who does not run the code, but the program itself.
It could be a simulation running for days, but only then one of the
agents in the simulated world decides to do something that fires off
the code in which you made changes.

Even a test suite is not a guarantee to catch this error.
This function could have several branches of execution, and not all
of them get tested. Sure, you can say: then the tests were not
designed
carefully enough.
But that’s the whole issue. If humans were able to always write
correct code, then a test suite wouldn’t be needed.
The tests themselfs can be wrong, and if you are a responsable
developer,
you will write a test suite for your test suite, to verify that your
tests are testing the right thing and do it completely.

I agree that a test suite can catch those problems, and often will.
But Rich implemented a test suite already into Clojure. At this
moment Clojure is doing these tests for you, and it will always test
it successfuly. It will not forget to do these tests, as a human test
suite writer could.
The current mechanism saves the test suite writer of that part of her
work.

Laurent PETIT

unread,
Mar 16, 2009, 8:25:14 PM3/16/09
to clo...@googlegroups.com
Hello,

Thanks for taking time thinking about this idea!

Your solution is indeed close to what I had in mind in terms of requirements. I was currently hacking with clojure java class Compiler to enhance Timothy's patch and add a variation on what you described.

My concern is that it should also work with AOT compilation, so I'm not sure if a solution just at the clojure clj code level would be sufficient then ?

Anyway, I'm facing difficulties with my understanding of the java code. Here are a couple of questions, if you have the answers, you're welcome ! :-) :

 * does the Compiler.load() process happen all in the same thread ? (And if yes, is that a guaranteed feature, or could that change in the future ?)
 * How do you correctly deref, ref-set! from java code by directly using a Var instance ?

--
Laurent


2009/3/17 Stephen C. Gilardi <sque...@mac.com>

Stephen C. Gilardi

unread,
Mar 16, 2009, 8:57:57 PM3/16/09
to clo...@googlegroups.com

On Mar 16, 2009, at 8:25 PM, Laurent PETIT wrote:

Hi Laurent,

> Your solution is indeed close to what I had in mind in terms of
> requirements. I was currently hacking with clojure java class
> Compiler to enhance Timothy's patch and add a variation on what you
> described.

Cool. I look forward to seeing what you come up with.

> * does the Compiler.load() process happen all in the same thread ?
> (And if yes, is that a guaranteed feature, or could that change in
> the future ?)

Compiler.load() appears to execute in a single thread currently. I'm
not aware of any guarantee about that. As a general rule, anything
that's not documented by Rich is eligible to be changed in the future.
In thinking about how that might work, it seems to me that making a
single load multithreaded would be more complex than it would be
worth, but no guarantees.

> * How do you correctly deref, ref-set! from java code by directly
> using a Var instance ?

ref-set is an operation on refs. deref can be applied to refs.

myRef.set(anObject);

myRef.deref();

Or, using the fine clojure.contrib.repl-utils:

user=> (source ref-set)
(defn ref-set
"Must be called in a transaction. Sets the value of ref.
Returns val."
[#^clojure.lang.Ref ref val]
(. ref (set val)))
nil
user=> (source deref)
(defn deref
"Also reader macro: @ref/@agent/@var/@atom/@delay/@future. Within a
transaction,
returns the in-transaction-value of ref, else returns the
most-recently-committed value of ref. When applied to a var, agent
or atom, returns its current state. When applied to a delay, forces
it if not already forced. When applied to a future, will block if
computation not complete"
[#^clojure.lang.IDeref ref] (.deref ref))
nil
user=> (show clojure.lang.Ref)
=== public clojure.lang.Ref ===
[ 0] <init> (Object)
...
[10] deref : Object ()
...
[46] set : Object (Object)
...
[53] wait : void (long,int)
nil
user=> (show clojure.lang.Ref 46)
#<Method public java.lang.Object
clojure.lang.Ref.set(java.lang.Object)>
user=> (show clojure.lang.Ref 10)
#<Method public java.lang.Object clojure.lang.Ref.deref()>
user=>

--Steve

Laurent PETIT

unread,
Mar 16, 2009, 9:06:23 PM3/16/09
to clo...@googlegroups.com
Hello again,

2009/3/17 Stephen C. Gilardi <sque...@mac.com>
On Mar 16, 2009, at 8:25 PM, Laurent PETIT wrote:

Hi Laurent,


Your solution is indeed close to what I had in mind in terms of requirements. I was currently hacking with clojure java class Compiler to enhance Timothy's patch and add a variation on what you described.

Cool. I look forward to seeing what you come up with.

Well, that's not working as expected currently :-(


 * does the Compiler.load() process happen all in the same thread ? (And if yes, is that a guaranteed feature, or could that change in the future ?)

Compiler.load() appears to execute in a single thread currently. I'm not aware of any guarantee about that. As a general rule, anything that's not documented by Rich is eligible to be changed in the future. In thinking about how that might work, it seems to me that making a single load multithreaded would be more complex than it would be worth, but no guarantees.

OK.
 


 * How do you correctly deref, ref-set! from java code by directly using a Var instance ?

ref-set is an operation on refs. deref can be applied to refs.

Sorry, it's late here, and I'm posting wrong questions :-$.

The real one was : how to correctly get the thread bound value, and change the thread bound value of a Var instance, from within java code ?


Stephen C. Gilardi

unread,
Mar 16, 2009, 9:17:20 PM3/16/09
to clo...@googlegroups.com

On Mar 16, 2009, at 9:06 PM, Laurent PETIT wrote:

> The real one was : how to correctly get the thread bound value, and
> change the thread bound value of a Var instance, from within java
> code ?

You can set the thread-bound value with "set" (defined in Var.java).
You get the thread-bound value with "get" or "deref" (also in Var.java).

Note that as with a deref in Clojure, if a var has no thread local
binding, "get" will return its root binding or throw an exception if
it has none.

--Steve

Laurent PETIT

unread,
Mar 16, 2009, 9:20:15 PM3/16/09
to clo...@googlegroups.com
2009/3/17 Stephen C. Gilardi <sque...@mac.com>

OK, so that's what I was doing ... seems like my error is elsewhere,

thanks for the help,

--
laurent

--Steve




--
Cordialement,

Laurent PETIT

Christophe Grand

unread,
Mar 17, 2009, 4:44:31 AM3/17/09
to clo...@googlegroups.com
How do you cope with type-hinted vars or macros? (ok #'declare does not
work for macros neither)

With autodef, one could have to either move the definition or add a
declare just to be able to add a type hint.

Christophe


Stephen C. Gilardi a écrit :


--
Professional: http://cgrand.net/ (fr)
On Clojure: http://clj-me.blogspot.com/ (en)


Elena

unread,
Mar 17, 2009, 5:02:58 AM3/17/09
to Clojure
On Mar 17, 12:15 am, "Stephen C. Gilardi" <squee...@mac.com> wrote:
> If *autodef-unresolved-symbols* is true, and if "a" has never been  
> mentioned before, this interaction with Clojure:
>
>         user=> a
>         java.lang.Exception: Unable to resolve symbol: a in this context
>
> would become:
>
>         user=> a
>         java.lang.IllegalStateException: Var user/a is unbound.

Is an exception needed here? Don't exceptions mean computing has been
aborted and shouldn't we use them to signal errors, not warnings?
Would a simple message from Clojure (a special formatting to allow the
IDE to highlight it) be better?

> Under this system:
>
>         - the behavior is optional at the repl. anybody not using it sees no  
> change in behavior there
>         - Clojure would relax its ordering requirements in source files while  
> still ensuring that all forward references are satisfied by the end of  
> each file.
>         - any vars that are intended to be unbound would (still) have to be  
> def'd explicitly.

That would accomplish what we are talking about here. Thanks for
taking time to explore the idea.

Michael Wood

unread,
Mar 17, 2009, 6:46:16 AM3/17/09
to clo...@googlegroups.com
On Tue, Mar 17, 2009 at 11:02 AM, Elena <egar...@gmail.com> wrote:
>
> On Mar 17, 12:15 am, "Stephen C. Gilardi" <squee...@mac.com> wrote:
>> If *autodef-unresolved-symbols* is true, and if "a" has never been
>> mentioned before, this interaction with Clojure:
>>
>>         user=> a
>>         java.lang.Exception: Unable to resolve symbol: a in this context
>>
>> would become:
>>
>>         user=> a
>>         java.lang.IllegalStateException: Var user/a is unbound.
>
> Is an exception needed here? Don't exceptions mean computing has been
> aborted and shouldn't we use them to signal errors, not warnings?
> Would a simple message from Clojure (a special formatting to allow the
> IDE to highlight it) be better?

I understand why people want to be able to do things like this:

(defn b [] (a))
(defn a [] (...))

But that's completely different from the above. The above is more like:

(a)
(defn a [] (...))

Why would you want that to warn and not be an error? What would you
expect it to do if it was just a warning?

i.e. at the REPL, what would you expect that to print at each step.

user=> (a)
???
user=> (defn a [] (...))
#'user/a

--
Michael Wood <esio...@gmail.com>

Elena

unread,
Mar 17, 2009, 7:01:24 AM3/17/09
to Clojure
On Mar 17, 10:46 am, Michael Wood <esiot...@gmail.com> wrote:
> I understand why people want to be able to do things like this:
>
> (defn b [] (a))
> (defn a [] (...))

That's what I'm asking for.

> But that's completely different from the above.  The above is more like:
>
> (a)
> (defn a [] (...))
>
> Why would you want that to warn and not be an error?  What would you
> expect it to do if it was just a warning?

I'd like it to be an error. Maybe I've not stated that clearly.

Michael Wood

unread,
Mar 17, 2009, 7:06:05 AM3/17/09
to clo...@googlegroups.com

I think you have been pretty clear right up until your previous e-mail
where you implied that:

(a)
(defn a ...)

should warn instead of error ;)

--
Michael Wood <esio...@gmail.com>

Elena

unread,
Mar 17, 2009, 7:20:39 AM3/17/09
to Clojure
On Mar 17, 11:06 am, Michael Wood <esiot...@gmail.com> wrote:
> I think you have been pretty clear right up until your previous e-mail
> where you implied that:
>
> (a)
> (defn a ...)
>
> should warn instead of error ;)

You are right, I misread the example and wrongly agreed to it.

I wanted to say that entering:

(defn a []
(b))

should issue a warning (and I don't think an exception is the right
way to warn the user). Then entering:

(a)

should issue an error, since 'b' is not bound. AFAIK, Lisp systems
would then allow you to enter the missing definition and restarting
the failed evaluation. Interactive development with steroids ^_^

Thanks for pointing out my mistake.

Stephen C. Gilardi

unread,
Mar 17, 2009, 7:39:37 AM3/17/09
to clo...@googlegroups.com

On Mar 17, 2009, at 4:44 AM, Christophe Grand wrote:

> How do you cope with type-hinted vars or macros? (ok #'declare does
> not
> work for macros neither)
>
> With autodef, one could have to either move the definition or add a
> declare just to be able to add a type hint.

The class of vars you're talking about are vars whose metdata and/or
value is needed at compile time. autodef as I've described it would
not help with those. To operate properly, they would still need to be
declared and/or defined before code that uses them is compiled.

The common theme is that all vars must have complete definitions
before their metadata and/or value is used. The vars you mention are
used earlier than others.

I think there is the potential for a good deal of confusion in the
cases you mention. Macros that were autodef'd because calls to them
were compiled into other functions would be called from those sites if
they were ordinary functions. Compiled code for hinted vars would not
benefit from the hints.

On the other side of the argument, the situation with autodef is
exactly the same as a policy (implemented by hand) of declaring all
vars you wish to define out of order using un-hinted declares. Autodef
simply makes that process automatic.

A complete solution would include a provision like "require for
syntax" (and likely other kinds of require/loading) that would allow a
module system to supply the compiler with all it needs independent of
the ordering of functions within a module or modules within a system.

--Steve

Stephen C. Gilardi

unread,
Mar 17, 2009, 7:49:26 AM3/17/09
to clo...@googlegroups.com

On Mar 17, 2009, at 7:20 AM, Elena wrote:

> I wanted to say that entering:
>
> (defn a []
> (b))
>
> should issue a warning (and I don't think an exception is the right
> way to warn the user).

The autodef I described would not warn, nor throw an exception in this
case.

I think "warn on autodef" would be a good feature at the repl. If it
were controlled by a var (say, *warn-on-autodef*), it could be
optional at the repl and suppressed in the case of loading source files.

--Steve

Rich Hickey

unread,
Mar 17, 2009, 8:23:37 AM3/17/09
to Clojure
I remain opposed, and here are some more reasons:

when you say

(def foo [x]
(bar x 42))

you are as likely to be referring to a forgot-to-require bar-lib as
you are to a to-be-defined bar.

The compiler can only default the latter, by interning bar in the
current namespace. There is no notion of compiling with a placeholder,
the name must be resolved to something. Should you really intend the
former, you end up with a mess, as you add (:require bar-lib) to your
ns call only to have it fail with a conflict - bar already defined in
your-ns.

Then you have to ns-unmap bar and retry. This is a big pain and one
you encounter all the time in Common Lisp, where the reader has auto-
interning characteristics similar to what is being discussed here.

Anything based on a unit-of-compilation concept has real problems for
Clojure, which generally treats a program as a stream of expressions.
Looking ahead is not an option, especially at the repl and other
streaming scenarios.

The biggest reason is - I'm not having the problems you are
describing, and neither are other experienced Clojure developers -
many of whom use the repl a lot.

Early on, I considered this a theoretical argument, but might have
been persuaded to reconsider if it kept coming up, but it didn't, and
doesn't.

(declare x y z foo bar baz ...)

is such a simple way to delay some decisions and sketch, I do not
consider it a serious impediment.

Rich

Laurent PETIT

unread,
Mar 17, 2009, 8:47:05 AM3/17/09
to clo...@googlegroups.com
Hello Rich,

2009/3/17 Rich Hickey <richh...@gmail.com>

I remain opposed, and here are some more reasons:

when you say

(def foo [x]
 (bar x 42))

you are as likely to be referring to a forgot-to-require bar-lib as
you are to a to-be-defined bar.

The compiler can only default the latter, by interning bar in the
current namespace. There is no notion of compiling with a placeholder,
the name must be resolved to something. Should you really intend the
former, you end up with a mess, as you add (:require bar-lib) to your
ns call only to have it fail with a conflict - bar already defined in
your-ns.

Then you have to ns-unmap bar and retry. This is a big pain and one
you encounter all the time in Common Lisp, where the reader has auto-
interning characteristics similar to what is being discussed here.

Well, I dedicated some time on this, as a general exercise to understand a little bit more clojure internals, and as a specific exercise on the topic.

I was trying to implement something a little bit more interesting than what you are describing above : given a "unit of compilation", every "missing symbol" is added to a list specific to the current unit of compilation, and at the end of the unit of compilation : either all symbols have finally been resolved, either at least one did not => and then the unit of compilation automatically unmaps all symbols in the list - leaving the namespace clean.

What do I call a unit of compilation ? the limits of a unit of compilation are easy to spot I -maybe too naively ? - think : "top level" call to eval, compile, or one of the "load" flavors.

Anything based on a unit-of-compilation concept has real problems for
Clojure, which generally treats a program as a stream of expressions.

I guess it's currently not totally true, given e.g. that load, ... install bindings for a substream of the expressions it manages ?
(But maybe I'm wrong here, please excuse me if this does not make sense - just trying to understand)

Looking ahead is not an option, especially at the repl and other
streaming scenarios.

The biggest reason is - I'm not having the problems you are
describing, and neither are other experienced Clojure developers -
many of whom use the repl a lot.

Well, this above other things is indeed sufficient to place priority on other functionalities ;-)

Regards,
 
--
Laurent

Laurent PETIT

unread,
Mar 17, 2009, 5:52:05 PM3/17/09
to clo...@googlegroups.com
2009/3/17 Stephen C. Gilardi <sque...@mac.com>
On Mar 16, 2009, at 8:25 PM, Laurent PETIT wrote:

Hi Laurent,


Your solution is indeed close to what I had in mind in terms of requirements. I was currently hacking with clojure java class Compiler to enhance Timothy's patch and add a variation on what you described.

Cool. I look forward to seeing what you come up with.

I give up on this one. I've now been half convinced that it's even less an ideal solution than I expected at first, and I prefer use the little free time I have to enhance clojuredev.

regards,

--
laurent

Stephen C. Gilardi

unread,
Mar 17, 2009, 6:24:57 PM3/17/09
to clo...@googlegroups.com

On Mar 17, 2009, at 5:52 PM, Laurent PETIT wrote:

> I give up on this one. I've now been half convinced that it's even
> less an ideal solution than I expected at first, and I prefer use
> the little free time I have to enhance clojuredev.

Sounds good. Thanks for closing the loop on this.

--Steve

Elena

unread,
Mar 17, 2009, 6:59:12 PM3/17/09
to Clojure
On 17 Mar, 13:23, Rich Hickey <richhic...@gmail.com> wrote:
> I remain opposed, and here are some more reasons:
>
> when you say
>
> (def foo [x]
>   (bar x 42))
>
> you are as likely to be referring to a forgot-to-require bar-lib as
> you are to a to-be-defined bar.
>
> The compiler can only default the latter, by interning bar in the
> current namespace.

I don't think having the compiler guessing what I mean to be a cool
idea. It reminds me of the so-called C++ template instantiation
problem (I'd say "nightmare") where the compiler tries several ways to
instantiate a template until it founds a way which works, and which
couldn't be the way you intended if you are not skilled enough (and
even then...). So I'll always vote for a predictable interpretation.
As if my vote had any value :-D

> There is no notion of compiling with a placeholder,
> the name must be resolved to something. Should you really intend the
> former, you end up with a mess, as you add (:require bar-lib) to your
> ns call only to have it fail with a conflict - bar already defined in
> your-ns.

I forgot that Clojure is a compiler, not a interpreter/compiler as the
other lisps I've tried out. So there are some issues involved.

> Then you have to ns-unmap bar and retry. This is a big pain and one
> you encounter all the time in Common Lisp, where the reader has auto-
> interning characteristics similar to what is being discussed here.

Thank you Rich for saving us such a big pain indeed ^_^ As they say,
sometimes the cure is worst than the illness...

> The biggest reason is - I'm not having the problems you are
> describing, and neither are other experienced Clojure developers -
> many of whom use the repl a lot.
>
> Early on, I considered this a theoretical argument, but might have
> been persuaded to reconsider if it kept coming up, but it didn't, and
> doesn't.
>
> (declare x y z foo bar baz ...)
>
> is such a simple way to delay some decisions and sketch, I do not
> consider it a serious impediment.

That's very reasonable: you shouldn't solve issues which are not
bothering you or your fellows, more so when you know beforehand that a
solution could backfire. So why I'm experiencing such a discomfort?
And I'm not alone, someone else already confessed sharing my
discomfort (even if they are not fully aware of it). Because we are
not experienced Clojure developers, are we? ;-)

Jokes apart, as I stated before, I do agree that Clojure does the
right thing by requiring you to specify where it should look for a
symbol; still I think I shouldn't be bothered with declaring symbols
and/or ordering functions in a counter intuitive way. You can't
reproach my laziness after Clojure itself have embraced it, can you?
^_^

I thought about it, read again the answers of my fellow developers and
realized that we are not dealing with a limitation of the compiler
itself: we are dealing with a limitation of our current development
environment. Therefore the problem should be solved at the tools
level. For instance: we could wrap the REPL with code which checks for
missing definition errors and then gives the developer the choice
about what to do: to fix a typo or to automatically issue a
declaration against the REPL, followed by the rejected definition
again. If such functionality is provided by the IDE, then the auto
issued declarations could be automatically inserted at the top of the
source file, and we'd never have to deal with them.

To summarize: let's both preserve Clojure's sound sanity checks and
make computer do the boring job. Here in Italy we call it "having a
full barrel and a drunk wife". What about your country? ^_^

What do you think?

Elena

unread,
Mar 17, 2009, 7:14:16 PM3/17/09