I want to create an object with properties and methods in Clojure, I read that gen-class and proxy can do the job I need but its implementation is very confusing for me.
I want to use proxy to avoid AOT compilation steps, I read about it and I though I better learn how to use the easier of the two
Here is what I want to do in Clojure
Java code:
public class MyClass {
public float myFloat;
MyClass( float _myFloat ) {
myFloat = _myFloat
}
public void showNumber() {
println( myFloat );
}
}
I'm struggling to translate that code to Clojure using proxys, any help will be much appreciated
UPDATE:
Apparently deftype is more suitable for my purposes, but I'm still struggling with its implementation
Here is my Clojure code:
(deftype Particle [x y]
Object
(render [this]
(no-stroke)
(fill 200 30 180)
(ellipse x y 200 200)))
Thing is I need to specify a protocol which I'm not sure which one to use, so I'm using Object as I'm trying to create a java-class like object but I get the folloiwng error message:
Can't define method not in interfaces: render
I'm using quill which is a Processing port for Clojure if that helps
UPDATE 2:
OK I manage to get a working defprotocol and deftype combo, but there is 1 more thing I need to leran how to do and that is to add member variables or properties to my class, here is my clojure code:
(defprotocol ParticleProtocol
(update [this])
(render [this]))
(deftype Particle [position]
ParticleProtocol
(update [this])
(render [this]
(no-stroke)
(fill 200 30 180)
(ellipse (.x position) (.y position) 20 20)))
To this object I would like to add a couple of variables like radius among others, any ideas?
I agree that deftype (or possibly defrecord) is a better than proxy to do this in Clojure, but see my comments at the end to consider all possibilities.
For your question after UPDATE 2.
You can add "properties" to records by specifying them in the arglist:
(deftype Particle [position radius prop3 prop4]
...
)
Remember that types in Clojure are immutable, so there is no concept of setting properties after creating the entity. If some of the properties are optional, it is recommended best practice to create helper "factory" methods, like:
(defn make-particle
([position] (Particle. position nil nil nil))
([position radius] (Particle. position radius nil nil))
;; etc. add more here as needed
)
An option to consider is to drop types entirely and just use maps, which have within them whatever "properties/fields" you need. Types are useful when you need to implement abstractions. For your ParticleProtocol - what is the value it is providing? Protocols are meant to provide a way to have polymorphism, so will you have multiple implementations of this protocol?
Chas Emerick did an in depth flowchart of how to choose a data type in Clojure that may help you: http://cemerick.com/2011/07/05/flowchart-for-choosing-the-right-clojure-type-definition-form/
[Update showing example map implementation]:
To construct a map with a "property" and retrieve that property you would do:
(def mymap {:myfloat 3.1415926})
(println "myfloat has value:" (:myfloat mymap))
To provide additional functionality, such as a "render" function, just create a fn that accepts a map with the desired keys:
;; the details are bogus, just showing the syntax
(defn render [m]
(no-stroke)
(fill (:radius m) (:position m))
(do-something-else (:position m)))
For your update, if you meant to update the values in the particle map, then you need to create a new map, rather than updating an existing one.
(def myparticle {:position 100 :radius 25})
(defn change-pos [particle-map new-pos]
(assoc-in particle-map [:position] new-pos))
(let [new-particle (change-pos myparticle 300)]
(println new-particle))
;; prints out {:position 300 :radius 25}
;; orig myparticle still has value {:position 100 :radius 25}
;; or do it directly
(println (assoc myparticle :position 300))
;; prints out {:position 300 :radius 25}
You can add the "variables" next to position, like this:
(deftype Particle [position radius]
...
)
position and radius aren't really variables, they are more like final attributes. If you need to "vary" them, you should store atoms in them, like this:
(Particle. (atom (Position. 3 4)) (atom 5.0))
But you should really heed the advise of #m0skit0 to stop thinking in terms of objects and classes and start thinking in functions and immutable data structures.
Related
We are using chart.js with clojurescript and Reagent. Now I know that Chart.js has a chart.update() method to update the chart with new data. So the question is, how can I setup my component so that it renders the chart on :reagent-render but probably get :component-will-update to call the chart.update() method ?
Basically, is there a way to get a handle on the chart that is created from :reagent-render function in :component-will-update function ?
The usual pattern you follow in this case is to wrap the stateful/mutable object in a React component and use React's lifecycle methods.
The approach is described in detail in re-frame's Using-Stateful-JS-Component but this is how I tend to do it with D3:
(defn graph-render [graph-attrs graph-data]
;; return hiccup for the graph here
(let [width (:width graph-attrs)
height (:height graph-attrs)]
[:svg {:width width :height height}
[:g.graph]]))
(defn graph-component [graph-attrs graph-data]
(r/create-class
{:display-name "graph"
:reagent-render graph-render
:component-did-update (fn [this]
(let [[_ graph-attrs graph-data] (r/argv this)]
(update! graph-attrs graph-data)))
:component-did-mount (fn [this]
(let [[_ graph-attrs graph-data] (r/argv this)]
(init! graph-attrs graph-data)))}))
(defn container []
[:div {:id "graph-container"}
[graph-component
#graph-attrs-ratom
#graph-data-ratom]])
It is important to keep the outer/inner combination because React won't populate its props correctly otherwise.
Another thing to be carefully of is the return of the reagent/argv vector, which, as you can see, contains the props after the first item. I have seen (reagent/props comp) in the wiki page above but I have never tried it myself.
So I'm trying to make a Clojure macro that makes it easy to interop with Java classes utilizing the Builder pattern.
Here's what I've tried so far.
(defmacro test-macro
[]
(list
(symbol ".queryParam")
(-> (ClientBuilder/newClient)
(.target "https://www.test.com"))
"key1"
(object-array ["val1"])))
Which expands to the below
(.
#object[org.glassfish.jersey.client.JerseyWebTarget 0x107a5073 "org.glassfish.jersey.client.JerseyWebTarget#107a5073"]
queryParam
"key1"
#object["[Ljava.lang.Object;" 0x16751ba2 "[Ljava.lang.Object;#16751ba2"])
The desired result is:
(.queryParam
#object[org.glassfish.jersey.client.JerseyWebTarget 0x107a5073 "org.glassfish.jersey.client.JerseyWebTarget#107a5073"]
"key1"
#object["[Ljava.lang.Object;" 0x16751ba2 "[Ljava.lang.Object;#16751ba2"])
I guess the . is causing something to get evaluated and moved around? In which case the solution would to be to quote it. But how can I quote the results of an evaluated expression?
My goal is to convert maps into code that build the object by have the maps keys be the functions to be called and the values be the arguments passed into the Java functions.
I understand how to use the threading and do-to macros but am trying to make request building function data driven. I want to be able take in a map with the key as "queryParam" and the values as the arguments. By having this I can leverage the entirety on the java classes functions only having to write one function myself and there is enough of a 1 to 1 mapping I don't believe others will find it magical.
(def test-map {"target" ["https://www.test.com"]
"path" ["qa" "rest/service"]
"queryParam" [["key1" (object-array ["val1"])]
["key2" (object-array ["val21" "val22" "val23"])]] })
(-> (ClientBuilder/newClient)
(.target "https://www.test.com")
(.path "qa")
(.path "rest/service")
(.queryParam "key1" (object-array ["val1"]))
(.queryParam "key2" (object-array ["val21" "val22" "val23"])))
From your question it's not clear if you have to use map as your builder data structure. I would recommend using the threading macro for working directly with Java classes implementing the builder pattern:
(-> (ClientBuilder.)
(.forEndpoint "http://example.com")
(.withQueryParam "key1" "value1")
(.build))
For classes that don't implement builder pattern and their methods return void (e.g. setter methods) you can use doto macro:
(doto (Client.)
(.setEndpoint "http://example.com")
(.setQueryParam "key1" "value1"))
Implementing a macro using a map for encoding Java method calls is possible but awkward. You would have to keep each method arguments inside a sequence (in map values) to be a able to call methods with multiple parameters or have some convention for storing arguments for single parameter methods, handling varargs, using map to specify method calls doesn't guarantee the order they will be invoked etc. It will add much complexity and magic to your code.
This is how you could implement it:
(defmacro builder [b m]
(let [method-calls
(map (fn [[k v]] `(. (~(symbol k) ~#v))) m)]
`(-> ~b
~#method-calls)))
(macroexpand-1
'(builder (StringBuilder.) {"append" ["a"]}))
;; => (clojure.core/-> (StringBuilder.) (. (append "a")))
(str
(builder (StringBuilder.) {"append" ["a"] }))
;; => "a"
I have this small game world state, something like the following:
(defn odds [percentage]
(< (rand-int 100) percentage))
(defn world []
{:entities []})
(defn make-bird []
{:pos [(rand-int 100) (rand-int 100)]
:age 0
:dir (vec/dir (rand (. Math PI)))})
(defn generate-entities [entities]
(if (odds 10)
(conj entities (make-bird))
entities))
(defn update-entity [entity]
(-> entity
(update :pos (partial vec/add (:dir entity)))
(update :age inc)))
(defn update-entities [entities]
(vec (map update-entity entities)))
(defn old? [{age :age}]
(> age 10))
(defn prune-entities [entities]
(vec (filter #(not (old? %)) entities)))
(defn update-world [world]
(-> world
(update :entities generate-entities)
(update :entities update-entities)
(update :entities prune-entities)))
So update-world goes through three steps. First there's a 1/10 chance of generating a new bird entity, which flies in a random direction. Then it updates all birds, updating their position and incrementing their age. Then it prunes all old birds.
I use this same technique for generating particles systems. You can do fun stuff like (iterate update-world (world)) to get a lazy list of world states which you can consume at whatever frame rate you want.
However, I now have a game world with autonomous entities which roam around and do stuff, kind of like the birds. But I want to get a textual representation of what happened when evaluating update-world. For example, update-world would ideally return a tuple of the new world state and a vector of strings - ["A bird was born at [12, 8].", "A bird died of old age at [1, 2]."].
But then I really can't use (iterate update-world (world)) anymore. I can't really see how to do this.
Is this something you'd use with-out-string for?
If you want to enhance only your top-level function (update-world) in your case you can just create a wrapper function that you can use in iterate. A simple example:
(defn increment [n]
(inc n))
(defn logging-increment [[_ n]]
(let [new-n (increment n)]
[(format "Old: %s New: %s" n new-n) new-n]))
(take 3 (iterate logging-increment [nil 0]))
;; => ([nil 0] ["Old: 0 New: 1" 1] ["Old: 1 New: 2" 2])
In case you want to do it while collecting data at multiple level and you don't want to modify the signatures of your existing functions (e.g. you want to use it only for debugging), then using dynamic scope seems like a reasonable option.
Alternatively you can consider using some tracing tools, like clojure/tools.trace. You could turn on and off logging of your function calls by simply changing defn to deftrace or using trace-ns or trace-vars.
There are two potential issues with using with-out-str
It returns a string, not a vector. If you need to use a vector, you'll need to use something else.
Only the string is returned. If you are using with-out-str to wrap a side-effect (e.g., swap!), this might be fine.
For debugging purposes, I usually just use println. You can use with-out if you want control over where the output goes. You could even implement a custom stream that collects the output into a vector of strings if you wanted. You could get similar results with a dynamically bound vector that you accumulate (via set!) the output string (or wrap the vector in an atom and use swap!).
If the accumulated vector is part of the computation per se, and you want to remain pure, you might consider using a monad.
What about using clojure.data/diff to generate the string representation of changes? You could do something like this:
(defn update-world [[world mutations]]
(let [new-world (-> world
(update :entities generate-entities)
(update :entities update-entities)
(update :entities prune-entities))]
[new-world (mutations (clojure.data/diff world new-world))]))
Then you could do something like (iterate update-world [(world) []]) to get the ball rolling.
According to Om Next's documentation:
query->ast
(om.next/query->ast '[(:foo {:bar 1})])
Given a query expression return the AST.
ast->query
(om.next/ast->query ast)
Given a query expression AST, unparse it into a query expression.
Question: Why would one need these functions? That is, why would one need to directly manipulate a query abstract syntax tree (which I'm assuming are clojure maps that represent a query tree, along with some meta data) in om next?
There are some scenarios where you need to manipulate the query ast directly. In remote parsing mode, the parser expects your read functions to return either {:remote-name true } or a (possibly modified) {:remote-name AST-node} (which comes in as :ast in env). Most often you'll have to modify the AST to restructure it or add some data.
Example 1:
You have a query: [{:widget {:list [:name :created]}}]
The :widget part is pure UI related, your server doesn't need to know it exists, it only cares/knows about the :list.
Basically you'll have to modify the AST in the parser:
(defmethod read :list
[{:keys [ast query state]} key _ ]
(let [st #state]
{:value (om/db->tree query (get st key) st)
:remote (assoc ast :query-root true)}))
If you use om/process-rootsin your send function, it'll pick up the :query-root out of the ast and rewrite the query from [{:widget {:list [:name :created]}}] to [{:list [:name :created]}].
Example 2:
Another example would be when you want to mutate something at a remote:
(defmethod mutate 'item/update
[{:keys [state ast]} key {:keys [id title]}]
{:remote (assoc ast :params {:data {:id id :title title })})
Here you need to explicitly tell Om to include the data you want to send in the AST. At your remote you then pick apart :data to update the title at the given id
Most of the time you won't use the functions you described in your questions directly. The env available in every method of the parser has the ast in it.
Something I stumbled on, while trying to use Compassus:
Let's say you have a complex union/join query that includes parametric sub-queries. Something like this:
`[({:foo/info
{:foo/header [:foo-id :name]
:foo/details [:id :description :title]}} {:foo-id ~'?foo-id
:foo-desc ~'?foo-desc})]
Now let's say you want to set parameters so on the server you can parse it with om/parser and see those params as 3rd argument of read dispatch. Of course it's possible to write a function that would find all necessary parameters in the query and set the values. That's not easy though, and as I said - imagine your queries can be quite complex.
So what you can do - is to modify ast, ast includes :children :params key. So let's say the actual values for :foo-id and :foo-desc are in the state atom under :route-params key:
(defn set-ast-params [children params]
"traverses given vector of `children' in an AST and sets `params`"
(mapv
(fn [c]
(let [ks (clojure.set/intersection (-> params keys set)
(-> c :params keys set))]
(update-in c [:params] #(merge % (select-keys params (vec ks))))))
children))
(defmethod readf :foo/info
[{:keys [state query ast] :as env} k params]
(let [{:keys [route-params] :as st} #state
ast' (-> ast
(update :children #(set-ast-params % route-params))
om/ast->query
om.next.impl.parser/expr->ast)]
{:value (get st k)
:remote ast'}))
So basically you are:
- grabbing ast
- modifying it with actual values
you think maybe you can send it to server right then. Alas, no! Not yet. Thing is - when you do {:remote ast}, Om takes :query part of the ast, composes ast out of it and then sends it to the server. So you actually need to: turn your modified ast into query and then convert it back to ast again.
Notes:
set-ast-params function in this example would only work for the first level (if you have nested parametrized queries - it won't work),
make it recursive - it's not difficult
there are two different ways to turn ast to query and vice-versa:
(om/ast->query) ;; retrieves query from ast and sets the params based
;; of `:params` key of the ast, BUT. it modifies the query,
;; if you have a join query it takes only the first item in it. e.g. :
[({:foo/foo [:id]
:bar/bar [:id]} {:id ~'?id})]
;; will lose its `:bar` part
(om.next.impl.parser/ast->expr) ;; retrieves query from an ast,
;; but doesn't set query params based on `:params` keys of the ast.
;; there are also
(om/query->ast) ;; and
(om.next.impl.parser/expr->ast)
In clojure, it is possible to destructure some keys of a map like this:
(let [{:keys [cpp js]} {:cpp 88 :js 90}]
(println js); 90
(println cpp); 88
)
Is there a way to destructure all the keys of a map?
Maybe something like:
(let [{:all-the-keys} {:cpp 88 :js 90}]
(println js); 90
(println cpp); 88
)
Not really, and it wouldn't be a good idea. Imagine:
(let [{:all-the-keys} m]
(foo bar))
Are foo and bar globals? Locals? Keys you should extract from m? What should this code do if m sometimes contains a foo key, and foo is also a global function? Sometimes you call the global, and sometimes you call the function stored in m?
Ignoring the technical problems (which could be overcome), it is really a disaster for readability and predictability. Just be explicit about what keys you want to pull out; if you frequently want to pull out the same ten keys, you can write a simple macro like (with-person p body) that simplifies that common case for you.
This question is pretty old so you've probably forgotten about it, but it came up on google when I was trying to do the same thing, so if I post my solution it might help someone else out.
(defmacro let-map [vars & forms]
`(eval (list 'let (->> ~vars keys
(map (fn [sym#] [(-> sym# name symbol) (~vars sym#)]))
(apply concat) vec)
'~(conj forms 'do))))
This basically transforms the map {:cpp 88 :js 90} into the binding form [cpp 88 js 90] then constructs a let binding, along with performing some eval-jitsu to make sure that this happens at run time.
(def test-map {:cpp 88 :js 90})
(let-map test-map
(println js)
(println cpp))
;=> 90
;=> 88
You could write a macro to do this (effectively creating a mini-DSL), but I don't think it is a very good idea for the following reasons:
In order to create the right compile-time literals js and cpp, you would need to destructure the map at compile time. This would be quite limiting in terms of what you could do with it (you would have to specify the keys in advance, and it couldn't use in higher order functions, for example)
Macros are generally a bad idea when a simpler method would do the job (see below)
I'd recommend just using a simple doseq in your case to loop over the map:
(let [my-map {:cpp 88 :js 90}]
(doseq [[k v] my-map]
(println v)))
Note that:
You can use destructuring as above to extract both the key k and value v from each map entry
I used doseq rather than for because it is non-lazy and it seems in this example that you are using the loop only for the println side effects.
If instead you want a lazy sequence of values (88 90) then for would be appropriate.