#Erlang and recursion

1 messages ยท Page 1 of 1 (latest)

frosty sphinx
#

Hi, I've been playing around with Gleam for work and I came across some issues with recursion and Erlang. This is not necessarily an issue with Gleam.

I noticed that while the Gleam compiler is able to convert explicitly tail-recursive code into a loop for JavaScript, the TCO implemented by Erlang struggles quite a bit and causes gleeunit to crash (which I assume is due to a memory limit reached) (1st image)

Here's the code I've been using.

Is this a generally known issue in Erlang or is there something I've missed?

Another fun thing is that the JS and Erlang targets disagree on the result for tail_sum_even(300_000_000) (2nd image)

A playground for the Gleam programming language. Write, run, and share Gleam code in your browser.

vital pagoda
#

The BEAM implements proper tail call optimisation so the problem with your code is not with it not being tail call optimised

#

From gleeunit's output it looks like the test is killed because it's timing out, not because of a stack overflow

frosty sphinx
#

oh, ok. That makes sense

vital pagoda
#

The output is not the clearest but you can tell it's a timeout from the first line of the error

%% Unknown error: {timeout, ...
frosty sphinx
#

Oh, didn't notice that :D

vital pagoda
#

Oh yeah itโ€™s easy to miss!

frosty sphinx
#

how about the 2nd image? I don't see why the target should change the result

clever bison
#

the different targets have different semantics for numbers

#

your test is like an order of magnitude larger than javascript's max safe int

frosty sphinx
#

Hmm, it seems odd to me to have different behaviour on different targets but ig if it's intended...

clever bison
#

the different semantics are what makes the targets,, different

#

gleam isnt a virtual machine its a language that targets other virtual machines, its important to understand the thing you're targetting!

frosty sphinx
#

yes, ofc, but for example if I compile Rust code for using u128 for a target that doesn't natively support it, the compiler generates something that is slower but behaves in the same way

#

imo, targeting different targets should try to keep the behavior as similar as possible, but I'm no language developer, it's just what I expect intuitively.

sick quest
#

you can check out bigi if you want consistent handling of integers (unless your integer is bigger than 4 MB)

clever bison
#

abstracting away target-specific semantics is the compiler irrevocably taking a decision away from you as the developer. If, for example, gleam ints compiled to javascript BigInts then the consequences are:

  • all gleam code that works with numbers is slower on javascript because every number is forced to be a bigint
  • ffi with javascript code that works with numbers now involves boxing native js numbers to bigints
    • that means every dom api, every platform api that returns a number must be wrapped before it can be used
#

as @sick quest points out if you explicitly want target-agnostic semantics you have the power to opt into that through a package! the reverse is not really as true and would harm all gleam code as a consequence

frosty sphinx
#

Thanks for the clarifications! ๐Ÿ’œ

clever bison
#

i think it does surprise folks sometimes but i reckon its the right call

#

anyway bigi is a cool package so you should use it! ๐Ÿ˜„

sick quest
#

bigi is useful for libraries that need to work on both targets. if you're making an app where you know the target is Erlang, then you don't need it

signal phoenix
#

that JS uses numbers as it does, is the surprise for me.

frosty sphinx
#

JS is full of surprises ๐Ÿ’€

signal phoenix
#

a classic

slender raft