Prevent macro expansion in false branch of if expression - macros

In Clojure, the branch of an if expression that doesn't match the condition is not evaluated, so no exception is thrown in evaluating the below expression:
=> (if nil (/ 1 0))
nil
However, macros will still be expanded before evaluating the if, so you can still get exceptions like so:
=> (if nil (proxy [nil] []))
CompilerException java.lang.NullPointerException, compiling:(NO_SOURCE_PATH:1)
I'm writing a macro for which the name of an interface will sometimes be provided as an arg, in which case the macro will generate the code for a call to proxy. Other times, the interface arg will be nil, and then the macro expands to something like (if nil (proxy [nil] []), so I get the above exception. An SSCE would be:
=> (defmacro make-listener [listener-name & methods]
`(if ~listener-name
(proxy [~listener-name] []
~#(map (fn [m] `(~m [e#])) methods))))
#'user/make-listener
=> (make-listener java.awt.event.ActionListener actionPerformed)
#<Object$ActionListener$46793e3a user.proxy$java.lang.Object$ActionListener$46793e3a#ed5b2>
=> (make-listener nil)
CompilerException java.lang.NullPointerException, compiling:(NO_SOURCE_PATH:1)
How can I write the macro in a way that doesn't throw an exception when no interface arg is provided?

If listener-name is nil then the macro should do nothing i.e you need to check for listener-name at macro expansion (not in the code the macro emit).
(defmacro make-listener [listener-name & methods]
(if listener-name
`(proxy [~listener-name] []
~#(map (fn [m] `(~m [e#])) methods))))

Related

How to use a variable reference instead of it's value because it's nil at compilation time?

I'm wrapping my Appsignal instrumentation and everything works fine.
def handle_event("submit", %{"waitlist" => params}, socket) do
live_view_action(__MODULE__, "submit", socket, fn ->
{:noreply, socket}
end)
end
I wanted to move this to a decorator so I could do something like this:
#decorate instrument("submit")
def handle_event("submit", %{"waitlist" => params}, socket) do
{:noreply, socket}
end
# And in my decorator:
import Appsignal.Phoenix.LiveView, only: [live_view_action: 4]
def get_socket(context) do
Enum.find(context.args, fn arg ->
[{_, type} | _] = IEx.Info.info(arg)
if type == "tuple" && elem(arg, 0) == :socket do
arg
end
end)
end
def instrument(name, body, context) do
quote do
socket = unquote(get_socket(context))
live_view_action(unquote(context.module), unquote(name), socket, fn ->
unquote(body)
end)
end
end
socket is always nil in the context at compilation time so I can't even run my project.
How can I use the value of socket at runtime where I know the socket won't be nil?
I'm not familiar with decorators, but it seems like yours could be a problem with macro hygiene. What does the result of get_socket(context) look like? If it's more like {:socket, [], __MODULE__} than {:socket, [], nil}, that could be your problem.
You might try replacing unquote(get_socket(context)) with unquote(Macro.var(:socket, nil))?
See Macro.var/2

Future failure in Clojure

In Scala a future can fail and this can be found out asynchronously:
f onComplete {
case Success(_) => println("Great!")
case Failure(t) => println("An error has occurred: " + t.getMessage)
}
How would you 'translate' this into Clojure? My reading leads me to believe that the Clojure future/promise model is not as powerful as Scala's, and you can't just catch the failure like this. So what to do instead?
A Scala future never needs to be asked for it's value - when it is good and ready it will tell you what happened (including whether it failed - that's the crux of this question). This is what I meant by 'asynchronously'. A Scala future can be in one of three possible states - uncompleted, completed with failure, completed with success.
A typical example of a use case in Scala is a remote call that returns a Future[T], where T is the type of what you really want to get back. If the remote JVM is down then after a timeout the case Failure(t) will happen.
This is quite a straightforward model to work with. In the question I was asking for a simple alternative. As a side-comment it would be good to hear that Clojure intends to adopt the Scala Futures model at some point.
I remember futures in Scala are monads so searched algo.monads and fluokitten for something suitable. Finally I found Lenardo Borges' imminent library. I think it's what you want.
With this namespace declaration in place
(ns imminent-proof.core
(:require [imminent.core :as i]
[clojure.core.match :refer [match]])
(:import [imminent.result Success Failure]))
This is the failure case
(-> (i/future (/ 1 0))
(i/on-complete #(match [%]
[{Success v}] (prn "success: " v)
[{Failure e}] (prn "failure: " e))))
This the success case
(-> (i/future (Thread/sleep 1000) 42)
(i/on-complete #(match [%]
[{Success v}] (prn "success: " v)
[{Failure e}] (prn "failure: " e))))
And this the timeout case
(-> (i/future (Thread/sleep 1000) 42)
(i/await 500)
(i/on-complete #(match [%]
[{Success v}] (prn "success: " v)
[{Failure e}] (prn "failure: " e))))
I wonder if Clojure need specific construct to handle this situation with failed futures. The following line gives me the same functionality:
(defn f-cond[f func-ok func-fail]
(future (try (func-ok #f) (catch Exception e (func-fail e)))))
Then:
#(f-cond (future (throw (Exception. "hi")))
identity #(println "Failed: " (.getCause %)))
results in
Failed: #<Exception java.lang.Exception: hi>
the future macro is just wrapping a Java Future, and the deref reader macro is just syntax sugar for calling .get() against the future:
user=> (source future)
(defmacro future
"Takes a body of expressions and yields a future object that will
invoke the body in another thread, and will cache the result and
return it on all subsequent calls to deref/#. If the computation has
not yet finished, calls to deref/# will block, unless the variant of
deref with timeout is used. See also - realized?."
{:added "1.1"}
[& body] `(future-call (^{:once true} fn* [] ~#body)))
nil
user=> (source future-call)
(defn future-call
"Takes a function of no args and yields a future object that will
invoke the function in another thread, and will cache the result and
return it on all subsequent calls to deref/#. If the computation has
not yet finished, calls to deref/# will block, unless the variant
of deref with timeout is used. See also - realized?."
{:added "1.1"
:static true}
[f]
(let [f (binding-conveyor-fn f)
fut (.submit clojure.lang.Agent/soloExecutor ^Callable f)]
(reify
clojure.lang.IDeref
(deref [] (deref-future fut))
clojure.lang.IBlockingDeref
(deref
[ timeout-ms timeout-val]
(deref-future fut timeout-ms timeout-val))
clojure.lang.IPending
(isRealized [] (.isDone fut))
java.util.concurrent.Future
(get [] (.get fut))
(get [_ timeout unit] (.get fut timeout unit))
(isCancelled [] (.isCancelled fut))
(isDone [] (.isDone fut))
(cancel [_ interrupt?] (.cancel fut interrupt?)))))
nil
user=>
So testing for failure is no different than in java: you catch an ExecutionException, see java doc for Future:
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html#get()
So the solution is to catch the exception from the deref, as shown in other answers.

Flatten arbitrarily nested List in Scala

def flatten(l: List[_]): List[_] = {
def iflatten(l: List[_], ret: List[_]): List[_] = l match {
case Nil => ret
case h :: Nil =>
if( h.isInstanceOf[List[_]]) { iflatten(h, ret) }
else {
l.head :: ret
iflatten(l.tail, ret)
}
}
}
I know there are multiple ways to do this, and I'm not 100% sure my way is correct. I would like to test it but one issue I'm running into is in the second case statement where I call:
... { iflatten(h, ret) }
I am getting the compiler error:
error: type mismatch;
found : Unit
required: List[?]
I'm trying to work through these type issues to learn more about the typesystem as it's different than what I've worked with in the past. Any suggestions as to why the compiler is complaining would be greatly appreciated.
I'm not getting the same error you are concerning iflatten(h,ret).
I am getting the found : Unit; required : List[?] error, but it refers to the fact that you are not calling iflatten in flatten itself : after defining it, you need to call the function at the end of flatten's definition.
def flatten(l: List[_]): List[_] = {
def iflatten(l: List[_], ret: List[_]): List[_] = l match {
case Nil => ret
case (h:List[_]) :: tail => iflatten(tail,iflatten(h,ret))
case h :: tail => iflatten(tail,h::ret)
}
iflatten(l,List()).reverse
}
As for the code itself, you can (and should) verify types when matching.
Also note that the case h :: Nil only matches 1-length list.
As for the algorithm, you need to call iflatten within itself (that's where the arbitrarily nesting takes place).
I think you're just missing a cast.
if( h.isInstanceOf[List[_]]) { iflatten(h.asInstanceOf[List[_]], ret) }
Alternately: It would be prettier with pattern matching.
h match {
case hList: List[_] =>
iflatten(hList, ret)
case _ =>
l.head :: ret
iflatten(l.tail, ret)
}
(caveat: This is just off the top of my head and I haven't put anything through a compiler)
edit - Marth's solution of merging that into the previous pattern match looks better than mine.
Actually, I suspect the problem lies in the fact that you define the inner method iflatten, but never call it, so that the outer method flatten doesn't return anything (ie defaults to a return type of Unit, conflicting with the stated return type of List[_]).
Try adding the following as the last line of the outer flatten method:
iflatten(l, Nil)
Beyond that, you have various other problems with your code, such as not handling all match cases: you handle the case of a list with one element - h :: Nil - but not several elements. You probably meant something like h :: theRest, and then use theRest somewhere - probably as your ret parameter for the recursive call.
You also use the check h.isInstanceOf[List[_]] (generally any use of isInstanceOf is a bad code smell in scala) but then try passing h into iflatten recursively without casting it as List[_] (for example, as in #ChristopherMartin's answer, although using asInstanceOf is an even bigger code smell). #Marth's answer gives a good example of how to avoid these explicit type checks.
I think this is something the Shapeless library is good at.
https://github.com/milessabin/shapeless/blob/master/examples/src/main/scala/shapeless/examples/flatten.scala
Sorry, but this code is very complicated. I tried to simplify it and got to this solution:
scala> :paste
// Entering paste mode (ctrl-D to finish)
def flatten(l : List[_]) : List[_] = l flatMap {
case l1 : List[_] => flatten(l1)
case otherwise => List(otherwise)
}
// Exiting paste mode, now interpreting.
flatten: (l: List[_])List[_]
scala> flatten(List(1,2,3))
res3: List[Any] = List(1, 2, 3)
scala> flatten(List(1,2,List(3,4)))
res4: List[Any] = List(1, 2, 3, 4)
scala> flatten(List(List(1,List(2),3),4,List(4,5)))
res5: List[Any] = List(1, 2, 3, 4, 4, 5)
After fixing the code (adding the call to iflat), I did the following refactorings:
Removed the inner method
Used the built in flatMap for the iteration (and hence could eliminate or simplify some case expressions)
Replaced the instanceOf with type guards
I think a simpler solution would be using the shapeless library (hint: look for the "boilerplate" part).

Curried function evaluates all arguements

I'm trying to figure out why my curried function operates in the following way. I built the function ensure to take a more function approach instead of multiple if-then statements that would accomplish the same thing.
I discovered a bug today will running some tests where if the condition in the first ensure function e.g. ensure(contents.hasNext && acc != null) is true, the false condition or second arguement still gets evaluated and becomes the overriding function.
I can fix the problem if I simple change this: ensure(contents.hasNext) to this: ensure(contents.hasNext && acc == null) but i'm struggling with WHY this is happening.
Is there a more obvious (or just better) solution to this?
def ensure[T](f: => Boolean)(truth: => T, lie: T) = if (f) truth else lie
def lines(): Stream[String] = {
def matchLine(text: String, acc: String): Stream[String] = text match {
...
case NewLine(string) =>
ensure(contents.hasNext && acc != null)(acc +: matchLine(contents.next, string),
ensure(contents.hasNext)(matchLine(contents.next, string), acc +: string +: empty))
...
}
ensure(contents.hasNext)(matchLine(contents.next, null), empty)
}
(truth: => T, lie: T)
This means that the expression given for the truth parameter, will be evaluated each time that truth is used within your function (and only then), while lie will be executed exactly once before your function starts executing. In other words: truth is passed by name and lie isn't. To achieve the behaviour you want, you'd need to pass both by name (on the other passing the condition by name is not really necessary since it will be evaluated exactly once at the beginning of the function in all cases):
ensure[T](f: Boolean)(truth: => T, lie: => T) = if (f) truth else lie
That said, I wouldn't agree that replacing if-then-else expressions with a function that's basically a wrapper around if-then-else, makes your code more functional.

clojure macro using gen-class doesn't create annotations

I'm trying to write a clojure macro that will be used to generate multiple Java classes at compile time. I've found that I can add annotations to a class when I invoke gen-class outside of a macro. However, when I try to use gen-class inside a macro, the compiled class doesn't have annotations.
I boiled my problem down to this example:
(gen-class
:name ^{Deprecated true} Test1
:prefix Test1-
:methods [[^{Deprecated true} getValue [] Integer]])
(defn Test1-getValue [] 42)
(defmacro create-test-class [name x]
(let [prefix (str name "-")]
`(do
(gen-class
:name ~(with-meta name {Deprecated true})
:prefix ~(symbol prefix)
:methods [[~(with-meta 'getValue {Deprecated true}) [] Integer]])
(defn ~(symbol (str prefix "getValue")) [] ~x))))
(create-test-class Test2 56)
When I compile this file, it creates a Test1.class and Test2.class - I inspect both with Eclipse, and find that Test1 has both class-level and method-level #Deprecated annotations, but Test2.class that has no annotations. When I use macroexpand, it looks as though my Test2.class should be annotated:
user=> (set! *print-meta* true)
true
user=> (macroexpand '(create-test-class Test2 56))
(do (clojure.core/gen-class :name ^{java.lang.Deprecated true} Test2 :prefix Test2- :methods [[^{java.lang.Deprecated true} getValue [] java.lang.Integer]]) (user/defn Test2-getValue [] 56))
What am I doing wrong here?
Meikel Brandmeyer answered the question here:
https://groups.google.com/forum/#!topic/clojure/Ee1bVwcUT-c
"quote the annotation in the macro. (with-meta name `{Deprecated true}). Note the backtick."
Here is the working macro:
(defmacro create-test-class [name x]
(let [prefix (str name "-")]
`(do
(gen-class
:name ~(with-meta name `{Deprecated true})
:prefix ~(symbol prefix)
:methods [[~(with-meta 'getValue `{Deprecated true}) [] Integer]])
(defn ~(symbol (str prefix "getValue")) [] ~x))))