# What is a top level function and what isn't it?

Hi community, I hope all of you are good…
I’d like to know why this functions ins’t a top level function?
Is it because the only thing that do is call other private function?

`````` defmodule Math do
def sin(x), do: do_sin(x)
defp do_sin(x), do: nil
end
``````

More context:
I’m learning about AST, and I had a challenge with understand why this implementation below:
defmodule TopSecret do

``````def decode_secret_message_part(ast, acc) do
Macro.prewalk(ast, acc,
fn
{operation, _, [{name, _, args} | _]} = new_ast, acc)  when operation in [:def,   :defp] ->
{new_ast, [parse_name_to_str(name, args) | acc]}

other, acc -> {other, acc}
end)
end
end
``````

Because this test always fail using that?!

``````
test "ignores not top-level function definition" do
string = """
defmodule Math do
def sin(x), do: do_sin(x)
defp do_sin(x), do: nil
end
"""

ast = TopSecret.to_ast(string)
acc = []

{actual_ast, actual_acc} = TopSecret.decode_secret_message_part(ast, acc)
assert actual_ast == ast
assert actual_acc == acc
end
``````

But again, I don’t understand why I’ve success.

Do you have a definition for what is or is not a “top level function” ? This is not a term I’ve heard before. Modules have public function and private functions, that’s it.

With what exact error?

Probably related to the fact that you walk (aka recurse) the AST, which is explicitely not required by the exercise. They ask you to consider just the passed node, and nothing else.

Also, nothing in the concept or exercise description seems to introduce the term “top-level function”, it would be nice to explain what you understand by that term, because as ben said, it is not a term that we use in Elixir, while in other languages I have heard it synonymously used with “prelude”, which means more or less “autoimported functions”, which in this context doesn’t really make sense.

I agree that “top level function” is not something well defined in Elixir.

By my reasoning, `defmodule` is it in your example.

I don’t know, too.

That’s because I guess it’s weird… For me looks the same thing…
Here the completely challenge:
https://exercism.org/tracks/elixir/exercises/top-secret

Do you know, what is the difference between them below?

``````def decode_secret_message_part(ast, acc) do
Macro.prewalk(ast, acc,
fn
{operation, _, [{name, _, args} | _]} = new_ast, acc)  when operation in [:def,   :defp] ->
{new_ast, [parse_name_to_str(name, args) | acc]}

{operation, _, [{:when, _, [{name, _, args} | _]} | _]}  = new_ast, acc)  when operation in [:def,   :defp] ->
{new_ast, [parse_name_to_str(name, args) | acc]}

other, acc -> {other, acc}
end)
end
end
``````
``````def decode_secret_message_part(
{operation, _, [{:when, _, [{name, _, args} | _]} | _]} = ast,
acc
)
when operation in [:def, :defp] do
{ast, [parse_name_to_str(name, args) | acc]}
end

def decode_secret_message_part({operation, _, [{name, _, args} | _]} = ast, acc)
when operation in [:def, :defp] do
{ast, [parse_name_to_str(name, args) | acc]}
end

def decode_secret_message_part(ast, acc), do: {ast, acc}

def do_decode(ast) do
Macro.prewalk(ast, [], &decode_secret_message_part/2)
end

``````

Why the first fail on the test that I show you and the second success ?

My guess is that this is a leftover name from folks with Ruby experience - you can define methods outside of any explicit class or module in Ruby, which go into the “top-level namespace”.

It’s not a common term in Elixir, since writing `def` outside of a module just gives an error.

In the specific case of that test, it means the function under test should be looking for `def` and `defp` that are NOT nested inside any other structures in the AST.

1 Like

Interesting, but for me it looks inside the module even that it fail.

I don’t know what I’ve couldn’t see!

For example, comparing the result of these functions:

``````ast1 = Code.string_to_quote!("defmodule Math do
def sin(x), do: do_sin(x)
defp do_sin(x), do: nil
end")

ast2 = Code.string_to_quote("defmodule MyCalendar do
def busy?(date, time) do
Date.day_of_week(date) != 7 and
time.hour in 10..16
end

def yesterday?(date) do
Date.diff(Date.utc_today, date)
end
end")
``````

Why ast1 ins’t a top-level func and ast2 is ?

Again “top level functions” are not a thing in Elixir. Assuming al2o3cr is right with their assumption about “top-lvel function” here means “a function not bound to a module”

And the thing you have to check here is if the current node of the AST is a `def`/`defp`. Whether or not this node has parents or childrens is none of your concern for the sake of this exercise.

At this point we do not even care whether this node, its (potential) parents or (potential) children make any semantic sense.

We only care whether this node defines a function, and what the name and args of this where.

Neither `ast1` nor `ast2` are functions. Both hold ASTs of a module definition. Both should fail if passed to your exercises function. as neither node is a `def` or `defp` but they are `defmodule`. The fact that there are `def` and `defp` in the “body” is not relevant.

1 Like

Those two ASTs are used to test different functions, so they aren’t directly comparable.

`ast1` is used to test `decode_secret_message_part`:

The intent of `decode_secret_message_part` is to NOT recurse into nested clauses.

OTOH

`ast2` is used to test `decode_secret_message`:

The intent of `decode_secret_message` is to recurse into nested clauses, so “top-level” is meaningless here.

My final conclusion is I shouldn’t concern with that at this moment.
I’m grateful to you for your support.

I think that is really hard explain all the context of the my question.
But right it’s enough to know that “top-level function” ins’t a concern in Elixir.