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

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

Related

Elixir: Variable undefined during AST expansion

I have a module like this, ast1 and ast2 look the same, but I get an error with rest undefined in second one. Can someone explain the problem?
defmodule PacketDef do
pk_def = {:pk_name, [
{:unk_int1, :int},
{:unk_int2, :int},
]}
{pkn, field_defs} = pk_def
field_decs = Enum.map(field_defs, fn
({var_name, var_type}) when var_type in [:int] ->
rest = Macro.var(:rest, __MODULE__)
dec_name = String.to_atom("decode_#{var_type}")
xvar_name = Macro.var(var_name, __MODULE__)
quote do
{:ok, unquote(xvar_name), unquote(rest)} = unquote(dec_name)(unquote(rest))
end
(_field_def) ->
nil
end)
ast1 = quote do
def decode(unquote(pkn), rest) do
{:ok, unk_int1, rest} = decode_int(rest)
{:ok, unk_int2, rest} = decode_int(rest)
{:ok, rest}
end
end
ast2 = quote do
def decode(unquote(pkn), rest) do
unquote_splicing(field_decs)
{:ok, rest}
end
end
IO.puts("ast1")
IO.inspect(ast1, width: 100)
IO.puts("ast2")
IO.inspect(ast2, width: 100)
def decode(unquote(pkn), rest) do
{:ok, unk_int1, rest} = decode_int(rest)
{:ok, unk_int2, rest} = decode_int(rest)
{:ok, rest}
end
# why get error *rest* here
def decode(unquote(pkn), rest) do
unquote_splicing(field_decs)
{:ok, rest}
end
def decode_int(<<b::32-little, rest::binary>>) do
{:ok, b, rest}
end
end
update
What I want to do is, given pk_def generated decode function like in ast1, but with fields decode is generated dynamically.
The problem lies with the function definition not header, specifically the line:
unquote_splicing(field_decs)
If you remove this line, the code will work. The reason is that when the field_decs AST is expanded using unquote_splicing, it makes a sub-call trying to unquote rest variable which fails. Fixing how your AST gets evaluated will fix this as well.
This looks like an XY Problem to me. I'm not exactly sure what you're trying to do here but when dealing with language extension and custom DSLs, you should break it down into multiple smaller and composable Macros (with the majority of functionality implemented in private functions) and should also take good care of macro hygiene. That will substantially reduce your code complexity and make it easier to deal with code expansion in general, since you won't have to deal with ASTs directly.

How do I implement a JavaScript-style callback?

I'm trying to implement a JavaScript-style callback. I have an application that uses a library (both are mine) and I need the application to be able to pass a closure or function to a method in the library, which then spawns a thread and inside the thread when a condition is met it will call the callback.
main.rs
fn main(){
welcome_message();
mylib::connect(|| println!("Connected to service! Please enter a command. (hint: help)\n\n"));
loop {
match prompt_input() {
true => {},
false => break,
}
}
}
lib.rs
pub fn connect<F>(resolve: F) -> (mpsc::Sender<Message>, mpsc::Receiver<Message>)
where F: Fn()
{
...
let receive_loop = Thread::scoped(move || {
for response in receiver.incoming_messages::<Message>(){
let json_string = match response.unwrap() {
Message::Text(txt) => txt,
_ => "".to_string(),
};
let message = json::Json::from_str(json_string.as_slice());
let message_json = message.unwrap();
if message_json.is_object() {
let ref something = receiver_tx;
let obj = message_json.as_object().unwrap();
let something_json = obj.get("lsri").unwrap();
let something = something_json.to_string().replace("\"", "");
match something.as_slice() {
"service#connected" => resolve(),
_ => println!("{}", type),
}
} else {
println!("Invalid service response");
}
}
});
...
}
Error
src/lib.rs:54:24: 54:38 error: the trait `core::marker::Send` is not implemented for the type `F` [E0277]
src/lib.rs:54 let receive_loop = Thread::scoped(move || {
^~~~~~~~~~~~~~
src/lib.rs:54:24: 54:38 note: `F` cannot be sent between threads safely
src/lib.rs:54 let receive_loop = Thread::scoped(move || {
^~~~~~~~~~~~~~
It doesn't need to be a closure that I pass, I could pass a function too. It doesn't need any arguments or return types, but I could add some dummy ones if that helps. I am VERY open to suggestions of other methods or ways to accomplish the same goal.
I have tried using:
Thread::spawn
FnMut()
Arc::new(resolve) (with implementation of .clone())
Arc::new(Mutex::new(resolve)) (with implementation of .lock())
Searching Google for examples
Reading the Rust book in it's entirety
Searching the error message for examples
All of the above in various configurations
Is this possible with Rust? Is there a better way?
Thank you for your time in advance.
Solution:
For anyone finding this in the future, per the instructions of the answer below I changed the signature of connect to the following, which allowed the callback to be passed into the thread.
pub fn connect<'a, T, F>(resolve: F) -> (mpsc::Sender<Message>, mpsc::Receiver<Message>)
where T: Send + 'a, F: FnOnce() -> T, F: Send + 'a
Try marking your F with the same restrictions as Thread::scoped:
fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T>
where T: Send + 'a, F: FnOnce() -> T, F: Send + 'a
specifically, bounding the type with the Send trait should clear the immediate error of
the trait core::marker::Send is not implemented for the type F

Scope of variable changed inside Future's OnSuccess call

I need to get back a variable that was changed inside a Future's onSuccess block. Here is my sample code.
def futureFunction(arg:Any):Any = {
implicit val timeout = Timeout(10 seconds)
var ret:Any = None
val f: Future[Any] = someActor ? arg
f.onSuccess {
case a:String => {
ret = 1
println(ret) //prints "1"
}
case a:Int => {
ret = 2
println(ret) //prints "2"
}
}
ret //returns None
}
ret returns as None and does not change to 1 or 2. So does this mean that value of variable ret inside the onSuccess block cannot be returned? Yet, this seems to work:
var a : Any = None
{
a = 1
println("inside "+ a ) //prints "inside 1"
}
println(a) // prints "1"
What can I do in the future onSuccess block so that value of ret is returned as 1or 2 depending on whether the future's result is an integer or a string? What are the scoping rules in this case for scala. (I am using akka). Any help is appreciated. Thanks.
The problem here is not of scoping but of timing.
First you're initializing ret to None.
Then you're sending the message arg to someActor, which returns a future.
After that, you set up a function to be called when the future completes, which, if all goes well, will assign a value of 1 or 2 to ret at some point in the future.
Last of all, you immediately return the value of ret, which is still None.
And at some point in the future, the future completes, and your onSuccess function runs changing the value of ret and then printing it. But of course that can't go back in time and change the value that was already returned earlier.
So, to answer your question, there is nothing you can do in the onSuccess that will go back in time and change the already returned value. There are two alternatives though. One alternative would be to block until the future completes, then determine whether to return 1 or 2. The other is to return a Future[Int] so the caller can decide whether or not they want to block on the result. The code for that is actually simpler than what you have:
def futureFunction(arg:Any):Future[Int] = {
implicit val timeout = Timeout(10 seconds)
val f: Future[Any] = someActor ? arg
f.map {
case a:String => 1
case a:Int => 2
}
}
If you do need to block, you can use Await.result, either inside or outside futureFunction depending on where you want to block.
In futureFunction, ret is returned before the onSuccess handler runs. ret will become 1 or 2 when that happens, but it is too late at that point.
What you want to use is Future.map
someActor ? arg map {
case a:String => 1
case a:Int => 2
}
Note that futureFunction will either have to return a Future, or you will have to make a call to Await.result inside the function to block until the result is available.

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.

Scala: return has its place

References:
Scala return keyword
handling errors in scala controllers
EDIT3
This is the "final" solution, again thanks to Dan Burton.
def save = Action { implicit request =>
val(orderNum, ip) = (generateOrderNum, request.remoteAddress)
val result = for {
model <- bindForm(form).right // error condition already json'd
transID <- payment.process(model, orderNum) project json
userID <- dao.create(model, ip, orderNum, transID) project json
} yield (userID, transID)
}
Then the pimp'd Either project method, placed somewhere in your application (in my case, an implicits trait that sbt root & child project(s) extends their base package object from:
class EitherProvidesProjection[L1, R](e: Either[L1, R]) {
def project[L1, L2](f: L1 => L2) = e match {
case Left(l:L1) => Left(f(l)).right
case Right(r) => Right(r).right
}
}
#inline implicit final def either2Projection[L,R](e: Either[L,R]) = new EitherProvidesProjection(e)
EDIT2
Evolution, have gone from embedded return statements to this little white dwarf of density (kudos to #DanBurton, the Haskell rascal ;-))
def save = Action { implicit request =>
val(orderNum, ip) = (generateOrderNum, request.remoteAddress)
val result = for {
model <- form.bindFromRequest fold(Left(_), Right(_)) project( (f:Form) => Conflict(f.errorsAsJson) )
transID <- payment.process(model, orderNum) project(Conflict(_:String))
userID <- dao.create(model, ip, orderNum, transID) project(Conflict(_:String))
} yield (userID, transID)
...
}
I have added Dan's onLeft Either projection as a pimp to Either, with the above "project" method, which allows for right-biased eitherResult project(left-outcome). Basically you get fail-first error as a Left and success as a Right, something that would not work when feeding Option outcomes to for comprehension (you only get Some/None outcome).
The only thing I'm not thrilled with is having to specify the type for the project(Conflict(param)); I thought the compiler would be able to infer the left condition type from the Either that is being passed to it: apparently not.
At any rate, it's clear that the functional approach obviates the need for embedded return statements as I was trying to do with if/else imperative approach.
EDIT
The functional equivalent is:
val bound = form.bindFromRequest
bound fold(
error=> withForm(error),
model=> {
val orderNum = generateOrderNum()
payment.process(model, orderNum) fold (
whyfail=> withForm( bound.withGlobalError(whyfail) ),
transID=> {
val ip = request.headers.get("X-Forwarded-For")
dao.createMember(model, ip, orderNum, transID) fold (
errcode=>
Ok(withForm( bound.withGlobalError(i18n(errcode)) )),
userID=>
// generate pdf, email, redirect with flash success
)}
)}
)
which is certainly a densely power packed block of code, a lot happening there; however, I would argue that corresponding imperative code with embedded returns is not only similarly concise, but also easier to grok (with added benefit of fewer trailing curlies & parens to keep track of)
ORIGINAL
Finding myself in an imperative situation; would like to see an alternative approach to the following (which does not work due to the use of return keyword and lack of explicit type on method):
def save = Action { implicit request =>
val bound = form.bindFromRequest
if(bound.hasErrors) return Ok(withForm(bound))
val model = bound.get
val orderNum = generateOrderNum()
val transID = processPayment(model, orderNum)
if(transID.isEmpty) return Ok(withForm( bound.withGlobalError(...) ))
val ip = request.headers.get("X-Forwarded-For")
val result = dao.createMember(model, ip, orderNum, transID)
result match {
case Left(_) =>
Ok(withForm( bound.withGlobalError(...) ))
case Right((foo, bar, baz)) =>
// all good: generate pdf, email, redirect with success msg
}
}
}
In this case I like the use of return as you avoid nesting several if/else blocks, or folds, or matches, or fill-in-the-blank non-imperative approach. The problem of course, is that it doesn't work, an explicit return type has to specified, which has its own issues as I have yet to figure out how to specify a type that satisfies whatever Play magic is at work -- no, def save: Result, does not work as the compiler then complains about implicit result now not having an explicit type ;-(
At any rate, Play framework examples provide la, la, la, la happy 1-shot-deal fold(error, success) condition which is not always the case in the real world™ ;-)
So what is the idiomatic equivalent (without use of return) to above code block? I assume it would be nested if/else, match, or fold, which gets a bit ugly, indenting with each nested condition.
So as a Haskeller, obviously in my mind, the solution to everything is Monads. Step with me for a moment into a simplified world (simplified for me, that is) where your problem is in Haskell, and you have the following types to deal with (as a Haskeller, I sort of have this fetish for types):
bindFormRequest :: Request -> Form -> BoundForm
hasErrors :: BoundForm -> Bool
processPayment :: Model -> OrderNum -> TransID
isEmpty :: TransID -> Bool
Let's pause here. At this point, I'm sort of cringing a bit at boundFormHasErrors and transIDisEmpty. Both of these things imply that the possibility of failure is injected into BoundForm and TransID respectively. That's bad. Instead, the possibility of failure should be maintained separate. Allow me to propose this alternative:
bindFormRequest :: Request -> Form -> Either FormBindError BoundForm
processPayment :: Model -> OrderNum -> Either TransError TransID
That feels a bit better, and these Eithers are leading into the use of the Either monad. Let's write up some more types though. I'm going to ignore OK because that is wrapped around pretty much everything; I'm fudging a little bit but the concepts will still translate just the same. Trust me; I'm bringing this back around to Scala in the end.
save :: Request -> IO Action
form :: Form
withForm :: BoundForm -> Action
getModel :: BoundForm -> Model
generateOrderNum :: IO OrderNum
withGlobalError :: ... -> BoundForm -> BoundForm
getHeader :: String -> Request -> String
dao :: DAO
createMember :: Model -> String -> OrderNum -> TransID
-> DAO -> IO (Either DAOErr (Foo, Bar, Baz))
allGood :: Foo -> Bar -> Baz -> IO Action
OK, now I'm going to do something a bit wonky, and let me tell you why. The Either monad works like this: as soon as you hit a Left, you stop. (Is it any surprise I chose this monad to emulate early returns?) This is all well and good, but we want to always stop with an Action, and so stopping with a FormBindError isn't going to cut it. So let's define two functions that will let us deal with Eithers in such a way that we can install a little more "handling" if we discover a Left.
-- if we have an `Either a a', then we can always get an `a' out of it!
unEither :: Either a a -> a
unEither (Left a) = a
unEither (Right a) = a
onLeft :: Either l r -> (l -> l') -> Either l' r
(Left l) `onLeft` f = Left (f l)
(Right r) `onLeft` _ = Right r
At this point, in Haskell, I would talk about monad transformers, and stacking EitherT on top of IO. However, in Scala, this is not a concern, so wherever we see IO Foo, we can just pretend it is a Foo.
Alright, let's write save. We will use do syntax, and later will translate it to Scala's for syntax. Recall in for syntax you are allowed to do three things:
assign from a generator using <- (this is comparable to Haskell's <-)
assign a name to the result of a computation using = (this is comparable to Haskell's let)
use a filter with the keyword if (this is comparable to Haskell's guard function, but we won't use this because it doesn't give us control of the "exceptional" value produced)
And then at the end we can yield, which is the same as return in Haskell. We will restrict ourselves to these things to make sure that the translation from Haskell to Scala is smooth.
save :: Request -> Action
save request = unEither $ do
bound <- bindFormRequest request form
`onLeft` (\err -> withForm (getSomeForm err))
let model = getModel bound
let orderNum = generateOrderNum
transID <- processPayment model orderNum
`onLeft` (\err -> withForm (withGlobalError ... bound))
let ip = getHeader "X-Forwarded-For" request
(foo, bar, baz) <- createMember model ip orderNum transID dao
`onLeft` (\err -> withForm (withGlobalError ... bound))
return $ allGood foo bar baz
Notice something? It looks almost identical to the code you wrote in imperative style!
You may be wondering why I went through all this effort to write up an answer in Haskell. Well, it's because I like to typecheck my answers, and I'm rather familiar with how to do this in Haskell. Here's a file that typechecks, and has all of the type signatures I just specified (sans IO): http://hpaste.org/69442
OK, so now let's translate that to Scala. First, the Either helpers.
Here begins the Scala
// be careful how you use this.
// Scala's subtyping can really screw with you if you don't know what you're doing
def unEither[A](e: Either[A, A]): A = e match {
case Left(a) => a
case Right(a) => a
}
def onLeft[L1, L2, R](e: Either[L1, R], f: L1 => L2) = e match {
case Left(l) = Left(f(l))
case Right(r) = Right(r)
}
Now, the save method
def save = Action { implicit request => unEither( for {
bound <- onLeft(form.bindFormRequest,
err => Ok(withForm(err.getSomeForm))).right
model = bound.get
orderNum = generateOrderNum()
transID <- onLeft(processPayment(model, orderNum),
err => Ok(withForm(bound.withGlobalError(...))).right
ip = request.headers.get("X-Forwarded-For")
(foo, bar, baz) <- onLeft(dao.createMember(model, ip, orderNum, transID),
err => Ok(withForm(bound.withGlobalError(...))).right
} yield allGood(foo, bar, baz) ) }
Note that variables on the left hand side of <- or = are implicitly considered to be vals since they are inside of a for block. You should feel free to change onLeft so that it is pimped onto Either values for prettier usage. Also, make sure you import an appropriate "Monad instance" for Eithers.
In conclusion, I just wanted to point out that the whole purpose of monadic sugar is to flatten out nested functional code. So use it!
[edit: in Scala, you have to "right bias" Eithers to make them work with for syntax. This is done by adding .right to the Either values on the right-hand side of the <-. No extra imports necessary. This could be done inside of onLeft for prettier-looking code. See also: https://stackoverflow.com/a/10866844/208257 ]
What about some nested defs?
def save = Action { implicit request =>
def transID = {
val model = bound.get
val orderNum = generateOrderNum()
processPayment(model, orderNum)
}
def result = {
val ip = request.headers.get("X-Forwarded-For")
dao.createMember(model, ip, orderNum, transID)
}
val bound = form.bindFromRequest
if(bound.hasErrors) Ok(withForm(bound))
else if(transID.isEmpty) Ok(withForm( bound.withGlobalError(...) ))
else result match {
case Left(_) =>
Ok(withForm( bound.withGlobalError(...) ))
case Right((foo, bar, baz)) =>
// all good: generate pdf, email, redirect with success msg
}
}
}
Scala internally uses the throw/catch mechanism to handle returns in places where returns are syntactically okay but it actually has to jump out of several methods. So you can either let it do this:
def save = Action { implicit request =>
def result(): Foo = {
/* All your logic goes in here, including returns */
}
result()
}
or, if you prefer, you can use your own data-passing throwable class (without stack trace):
import scala.util.control.ControlThrowable
case class Return[A](val value: A) extends ControlThrowable {}
def save = Action { implicit request =>
try {
/* Logic */
if (exitEarly) throw Return(Ok(blahBlah))
/* More logic */
}
catch {
case Return(x: Foo) => x
}
}
Or you could get a little fancier and add your own exception handling:
case class Return[A](val value: A) extends ControlThrowable {}
class ReturnFactory[A]{ def apply(a: A) = throw new Return(a) }
def returning[A: ClassManifest](f: ReturnFactory[A] => A) = {
try { f(new ReturnFactory[A]) } catch {
case r: Return[_] =>
if (implicitly[ClassManifest[A]].erasure.isAssignableFrom(r.value.getClass)) {
r.value.asInstanceOf[A]
} else {
throw new IllegalArgumentException("Wrong Return type")
}
}
}
(If you want to be able to nest the returnings, just rethrow the Return instead of throwing an IllegalArgumentException when the type doesn't match.) You can use this like so:
def bar(i: Int) = returning[String] { ret =>
if (i<0) ret("fish")
val j = i*4
if (j>=20) ret("dish")
"wish"*j
}
bar(-3) // "fish"
bar(2) // "wishwishwishwishwishwishwishwish"
bar(5) // "dish"
or in your particular case
def save = Action{ implicit request => returning[Foo] { ret =>
/* Logic goes here, using ret(foo) as needed */
}}
It's not built in, but it shouldn't be terribly hard to explain to people how to use this even if it's not so easy to understand how the capability is built. (Note: Scala does have built in break capability in scala.util.control.Breaks which uses something very much like this strategy.)
IMHO, seems the problem here is that you are executing business logic in a controller, and Play signatures don't ahem play nice with return values like this is secondary.
I'd recommend you incapsulate the
generateOrderNum,
processPayment,
createMember
calls behind a facade, and that return value can return the appropriate state of the business transaction, which can then be used to return the proper controller state.
Will update this answer with an example in a bit.
Edit:
This is pretty sloppy so double-check the syntax, but the gist of my answer is to move your business logic sequence into an external class which will leverage the Either/Left/Right you are already using, but now includes your check for empty Transaction ID in the Left response.
def save = Action {implicit request =>
val bound = form.bindFromRequest
if (!bound.hasErrors) {
val model = bound.get
val ip = request.headers.get("X-Forwarded-For")
val result = paymentService.processPayment(model, ip)
result match {
case Left(_) => Ok(withForm(bound.withGlobalError(...)))
case Right((foo, bar, baz)) => // all good: generate pdf, email, redirect with success msg
}
}
else Ok(withForm(bound))
}
class PaymentService {
def processPayment(model, ip): Either[Blah, Blah] = {
val orderNum = generateOrderNum()
val transID = processPayment(model, orderNum)
if (transID.isEmpty) Left(yadda)
else Right(dao.createMember(model, ip, orderNum, transID))
}
}
The only thing a little hokey here is the if/else for bound.hasErrors, but not sure of a clean way to fold that into the match.
Make sense?