Compilation error on anonymous function argument with multiple clauses

Given an extension with these definitions:
@event_handler [
type:
{:spark_function_behaviour, ChannelHandler.Plugs.Handler,
{ChannelHandler.Plugs.Handler.Function, 2}},
required: true
]

@event %Spark.Dsl.Entity{
name: :event,
target: Event,
args: [:name],
describe: """
Handles an event matching exactly `name`.

## Examples

event "create_post" do
handler fn {payload, bindings}, socket ->
# ...
end
end
""",
entities: [plugs: [@plug]],
schema: [
name: [
type: :string,
required: true,
doc: """
The event to match.
"""
],
handler: @event_handler
]
}
@event_handler [
type:
{:spark_function_behaviour, ChannelHandler.Plugs.Handler,
{ChannelHandler.Plugs.Handler.Function, 2}},
required: true
]

@event %Spark.Dsl.Entity{
name: :event,
target: Event,
args: [:name],
describe: """
Handles an event matching exactly `name`.

## Examples

event "create_post" do
handler fn {payload, bindings}, socket ->
# ...
end
end
""",
entities: [plugs: [@plug]],
schema: [
name: [
type: :string,
required: true,
doc: """
The event to match.
"""
],
handler: @event_handler
]
}
And this usage:
handlers do
event "create" do
plug Plugs.CastInput

handler fn
{%{"id" => id}, bindings}, socket ->
{:reply, {:ok, "Dataset #{id} created for karta #{bindings.karta.id}"}, socket}

_, socket ->
{:noreply, socket}
end
end
end
handlers do
event "create" do
plug Plugs.CastInput

handler fn
{%{"id" => id}, bindings}, socket ->
{:reply, {:ok, "Dataset #{id} created for karta #{bindings.karta.id}"}, socket}

_, socket ->
{:noreply, socket}
end
end
end
I get this error:
== Compilation error in file lib/channels_web/channels/test_channel/dataset_handler.ex ==
** (ArgumentError) cannot inject attribute @spark_dsl_config into function/macro because cannot escape #Function<6.112779023/2 in :elixir_compiler_2.__MODULE__/1>. The supported values are: lists, tuples, maps, atoms, numbers, bitstrings, PIDs and remote functions in the format &Mod.fun/arity
(elixir 1.14.2) lib/kernel.ex:3543: Kernel.do_at/5
(elixir 1.14.2) expanding macro: Kernel.@/1
/home/dorgan/dev/channels/lib/channels_web/channels/test_channel/dataset_handler.ex:1: (file)
(spark 0.3.5) /home/dorgan/dev/channels/lib/channels_web/channels/test_channel/dataset_handler.ex:1: Spark.Dsl.__before_compile__/1
== Compilation error in file lib/channels_web/channels/test_channel/dataset_handler.ex ==
** (ArgumentError) cannot inject attribute @spark_dsl_config into function/macro because cannot escape #Function<6.112779023/2 in :elixir_compiler_2.__MODULE__/1>. The supported values are: lists, tuples, maps, atoms, numbers, bitstrings, PIDs and remote functions in the format &Mod.fun/arity
(elixir 1.14.2) lib/kernel.ex:3543: Kernel.do_at/5
(elixir 1.14.2) expanding macro: Kernel.@/1
/home/dorgan/dev/channels/lib/channels_web/channels/test_channel/dataset_handler.ex:1: (file)
(spark 0.3.5) /home/dorgan/dev/channels/lib/channels_web/channels/test_channel/dataset_handler.ex:1: Spark.Dsl.__before_compile__/1
If I remove the second clause to the fn in the handler, then it works.
10 Replies
ZachDaniel
ZachDaniel3y ago
I can already imagine why that’s happening. Will fix it tonight or tomorrow
Big Hat Dorgan
Big Hat DorganOP3y ago
enjoy your vacation :)
Big Hat Dorgan
Big Hat DorganOP3y ago
I see that in CodeHelpers spark only handles single clause anonymous functions, so it would be a matter of generating more clauses here https://github.com/ash-project/spark/blob/3f84eb5ac97fd61550113d00f126058a5370ad65/lib/spark/code_helpers.ex#L139-L162 I think
GitHub
spark/code_helpers.ex at 3f84eb5ac97fd61550113d00f126058a5370ad65 ·...
Tooling for building DSLs in Elixir. Contribute to ash-project/spark development by creating an account on GitHub.
ZachDaniel
ZachDaniel3y ago
Yep, exactly. We’d want to give it a name based on the hash of all clauses though, so that each definition has the same name It’s probably a pretty simple change all things considered. I can merge a PR if you make one 😀
Big Hat Dorgan
Big Hat DorganOP3y ago
I'll give it a shot!
Big Hat Dorgan
Big Hat DorganOP3y ago
It seems we're already taking an md5 hash of the full quoted expression so I just added more clauses: https://github.com/ash-project/spark/pull/18
GitHub
Support multiple function clauses in anonymous functions by doorgan...
This adds support for anymous functions with multiple clauses. Before this change, this code would fail to compile: argument fn "foo" -> "bar" _ -> "default"...
ZachDaniel
ZachDaniel3y ago
Looks perfect! Actually, one small thing And maybe not important, but I wouldn’t have expected the “unquote_splicing” to work since it would be putting commas after function defs Can you loop over the defs and make a list of quoted expressions instead? Actually, dunno if that will work… I guess yours is tested and works so maybe I’m getting at nothing 😂
Big Hat Dorgan
Big Hat DorganOP3y ago
It seems to produce the correct ast:
No description
ZachDaniel
ZachDaniel3y ago
Let’s go with it then 👍 Merged. Will cut a release later. Thanks for the PR!
Big Hat Dorgan
Big Hat DorganOP3y ago
:KyouAYAYA_MM:

Did you find this page helpful?