aspose file tools*
The moose likes Clojure and the fly likes Clojure question Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Languages » Clojure
Bookmark "Clojure question" Watch "Clojure question" New topic
Author

Clojure question

Matthew Ng
Greenhorn

Joined: Apr 17, 2013
Posts: 3
Hello, I'm doing a school paper on Clojure but there are two questions that i just can't find answers to anywhere they are:

Are data types bound to variables and parameters at compile-time? run-time? a combination?

and also,

How are parameters passed? (Pass by value? Pass by reference? Pass by value-result? etc.)

If anybody knows the answers to these two questions I would greatly appreciate it thanks!
Sean Corfield
Ranch Hand

Joined: Feb 09, 2011
Posts: 267
    
    5

Since Clojure is (mostly) about immutable data, you can't tell the difference between pass by value and pass by reference, but in reality, it's pass by reference (under the hook, the generated Java bytecode behaves as if everything were of type Object).

I'd have to actually decompile some bytecode to see if a function declared with primitive arguments and called with primitive arguments really avoids boxing / unboxing but that's the only edge case I can think of where arguments might be other than type Object.

Clojure is strongly typed at run-time, not compile-time. Type hints are primarily for the purpose of avoiding reflection in calls to external code although a loop/recur can be type hinted and use primitives (longs, doubles) without boxing / unboxing in some cases - so the type hints guide compilation but are not enforced by it. Type-checking is performed at run-time.

At least, that's my understanding. As I say, you'd have to decompile some bytecode to be sure.

Does that answer your questions well enough?
Sean Corfield
Ranch Hand

Joined: Feb 09, 2011
Posts: 267
    
    5

Looks like you got an answer on the main Clojure list that cleared up some of my uncertainly around primitive hinted argument types. I experimented in the REPL and saw this behavior:

These will ensure that the argument to f1 is numeric (and can be cast to long) and that the return value of f2 is numeric (and will be cast to long). Try calling each function with 123.456 to see the behavior, as well as attempting to call each with "abc". If you put (println x) inside each function, you'll see more clearly that f1 only accepts numeric arguments, whereas f2 accepts any argument but type checks on the return. That also clearly indicates that type checking is done at run-time - but does influence the compiler's behavior (causing it to insert casts and type checks).

I think Marko's answer on the mailing list about pass-by-value is also probably clearer than mine but this is a good example to illustrate it:

If you call that with 1 - (f3 1) - you'll get back java.lang.Long so you can see that the primitive was boxed and passed by value (as a reference to an Object). Similarly (f3 123.456) will return java.lang.Double. Passing non-primitive types will just pass the Object "by value" (which will be a reference to that object). If you pass a mutable Object, you can call mutating methods on it inside the function, but as I said Clojure data structures are immutable so it's pretty much irrelevant that it really is pass by reference-as-value under the hood
Matthew Ng
Greenhorn

Joined: Apr 17, 2013
Posts: 3
Thanks for the detailed reply however, you did use a lot of computer science-lingo that i have not yet learned in my classes like boxing/unboxing, reflection calls, type hints, and primitive hinted argument types. Also, i don't actually have a Clojure interpreter i had alot of problems downloading it off the Clojure website, I would unzip the file and try to run the executable file but it would just freeze, and reinstalling didn't work either. (If you could direct me to a website with a Clojure download link that would be awesome as well)

Although, i didn't really understand the complicated stuff, correct me if i'm wrong but it seems like your saying since Clojure is run on the JVM platform all of its data structures are objects like in java so therefore its pass-by-reference, however, its hard to tell because Clojure uses immutable data structures. What kind of confused me is in your next post you say its pass by reference-as-value "under the hood". So is it like a combination of the two? Is that possible?

For my first questions you make it pretty clear that data types are bound to variables are run-time. Marko also says that since Clojure is dynamically typed it doesn't have a type assigned to it but there are optional type hints, which constrain the type at compile time. I'm not sure what that last part means because i've never heard of type hints before but if Clojure doesn't have a type assigned to it because its dynamically typed how can type hints "constrain the type at compile time".

Now, I'm going to go off and look up some of these words I don't understand and try to make out what all of you smart people are trying to say, thanks again for the help!
Sean Corfield
Ranch Hand

Joined: Feb 09, 2011
Posts: 267
    
    5

If you're brand new to Clojure, Clooj or LightTable are probably the easiest ways to get started. Make sure you have Java installed. Then either go here to get Clooj: https://github.com/arthuredelstein/clooj or here to get LightTable: http://lighttable.com

If you want to be a bit more adventurous, go to http://leiningen.org and install the lein shell script. Leiningen is the standard project management / build tool for Clojure and it takes care of downloading Clojure and any other dependencies you need. That's easy if you're on Mac or Linux, more work if you're on Windows since it doesn't have curl or wget preinstalled - you can get those as part of GOW - Gnu on Windows - from here: https://github.com/bmatzelle/gow/downloads (and then use lein.bat from the Leiningen website.

Clojure itself is just a Java library so you don't really "install" it. Clojure is not an interpreter - it is a compiler. All Clojure code is compiled to JVM bytecode on demand and then executed just like regular compiled Java code.

Boxing: Java automatically packages primitive values (long, double, etc) into an object of the appropriate type as needed (Long, Double).
Unboxing: Java automatically converts the Long object to a long primitive as needed (and similarly for other types).

Reflection: ... probably too much to explain right now, given where you are

On the other questions... Yes, Clojure runs on the JVM and uses Java's types inside so it has Java's primitive long and double types but otherwise everything is an Object of some sort (and long / double are "boxed" to Long / Double as needed). That means all arguments are type Object in JVM bytecode - except for the primitive type examples I showed - and so what is passed is a reference to the underlying data. But that "Object reference" is technically passed-by-value, and when you have functions that actually take primitive arguments, those are passed-by-value too. Does that make sense? You're passing an Object reference by value. This may help: http://www.javaworld.com/javaqa/2000-05/03-qa-0526-pass.html

On types, yes, all of Clojure's type checking happens at run-time. In the absence of any type hints declared on arguments or return types, Clojure compiles the code so arguments are type Object and return types are also Object. Wherever a more specific type is required at run-time, a cast is attempted and if the object's type is not compatible, you'll get a run-time exception. The type hints tell the compiler that you're only going to pass certain types and/or return certain types. It's actually a little more complex than that because the following code happily compiles and runs:

When you call (f4 42) it will return 84 and (f4 "abc") will fail on the + operation (can't cast String to Number). The type hint here isn't forcing the argument types or return types, but if you called Java methods on x inside the function, Clojure would assume it was a String and wouldn't add code to check that it really was that type.

So, bottom line: Clojure is pass by value (like Java) and does all its type-checking at run-time (unlike Java).
Matthew Ng
Greenhorn

Joined: Apr 17, 2013
Posts: 3
Okay, so these questions were way more complicated than i had expected but i was finally able to rattle my brain and make something come out for my paper, so heres what i have so far word-for-word perhaps you can tell me if this is all right, or if there's something i should add, etc:

Binding of data types: Are data types bound to variables and parameters at compile-time? run-time? a combination?
Clojure does all of its type-checking at run-time. Clojure first compiles code and converts it to type object(the return types are also object). When a more specific type is required at run-time a cast is attempted to fetch the specific type of that object. A run time exception will occur if the object’s type is not compatible. For example:

(defn f4 ^String [^String x] (+ x x))
User => (f4 42)
;= 84

Calling (f4 42) will yield 84; the result we were expecting. However, calling (f4 “abc”) will not work because of the ‘+’ operation. Clojure will call a cast for the object type and it will yield a String and a Number, these are not compatible so we will get a run-time exception. However, this will compile fine because during compilation Clojure simply converts the code into objects. The error occurs during run time when the cast is made to see what type the object is and if they are compatible or not.

This one is for the parameter passing:
Since Clojure is on the JVM platform it shares some of Java’s attributes, specifically its parameter passing. Clojure’s code is compiled to JVM bytecodes and then executed just like regular Java code. This means that all compiled code is type Object in JVM bytecode and is passed by value like Java.

EDIT: I finished my parameter passing section, its short but it doesn't have to be too long because the question has multiple parts and my answer for those parts were quote long.

Also, since you said everything is converted to an object, I also read in a text book(I think it was Clojure Programming by Chas Emerick) that "All Clojure code is made up of expressions. Each of these expressions evaluates to a single value.". Does this mean that Clojures subroutines always returns a value?

Thanks!
-Matt

P.S: Please lemme know if you would like me to give you credit or something.
Sean Corfield
Ranch Hand

Joined: Feb 09, 2011
Posts: 267
    
    5

The problem is you're just repeating back what I told you - and quoting my words - without understanding what I'm telling you. Sorry to be blunt about that. No, you cannot quote my answers in your homework.

You need to understand the questions and answers, you need to try things out in Clojure to make sure you understand.

You say "these questions were way more complicated than i had expected" but the questions are simple - and there are partial answers that are simple as well, but they are partial answers. How you answer those questions in your paper is going to depend on what the professors are looking for, how much knowledge they expect you to have, and how much they expect you to deduce from (successful) experimentation with Clojure. There are indeed complicated answers, because there are subtle issues at play in Clojure, but whether you're expected to know that is going to depend a lot on your course and your professors.

As someone said on the main Clojure mailing list, unless you fully understand the answers - and can try code out for yourself - you're not going to know how accurate people's answers are.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Clojure question