
Show HN: Fe – A tiny, embeddable language implemented in ANSI C - rxi
https://github.com/rxi/fe
======
as-j
Cool!

Something I wish project docs would always include is …why… and what. Why does
fe exist? Why did the orignal author spend a span of 6mo on it? What can it do
and what can't it do? Don't make people read between the lines. It can be just
to learn and have fun! But please don't make me read between the lines.

The overview is interesting:

* Supports numbers, symbols, strings, pairs, lambdas, macros

* Lexically scoped variables, closures

* Small memory usage within a fixed-sized memory region — no mallocs

* Simple mark and sweep garbage collector

* Easy to use C API

* Portable ANSI C — works on 32 and 64bit

* Concise — less than 800 sloc

Since I work in embedded Linux systems I always like looking at small
languages, using Lua at the moment. So it struck my interest, oooh this is
interesting.

The single fixed allocation is interesting, and odd. It then has gc...so why
On the not just use malloc the manage the pool? I wonder if the performance is
that much better?

But beyond print there's no IO library, so I guess it's a "toy" language,
maybe somewhere to learn a lisp flavor?

~~~
chucksmash
> Why does Fe exist.

Reply to one of the GitHub issues discusses it some[1].

>> What was the motivation to create fe if you already made aria?

> The same motivations I had writing aria: for the fun of programming it;
> trying to make something terse but still practical. Every line of code has a
> weight to it with consideration that would be unreasonable outside this kind
> of project: a project that exists just to exist. Each time you write
> something it becomes — or at least should become — more clear and more
> concise than the previous time, and if you repeat this, the original version
> is by comparison an over-engineered bloated mess. fe is a sequel to aria,
> and as such ended up smaller, simpler and faster

[1]: [https://github.com/rxi/fe/issues/3](https://github.com/rxi/fe/issues/3)

------
dccoolgai
Nice. One of the things that always bothers me about "project" languages is
(for lack of a better way to put it) the "look at how smart I am" bullshit
that makes thinking about real problems hard and that authors of such projects
seem unable to resist. At least from a cursory glance, this seems to avoid
that. My first impression is that of a "more accessible Lisp". Interesting.

~~~
thethirdone
I am not sure exactly what qualifies as ""look at how smart I am" bullshit",
but as someone making a toy language, exploring how a concept taken to its
extreme in a language re-contextualizes other features is the main purpose of
making it.

I have made a fair number of decisions against ergonomics in favor of less
objectively important ideals because I don't plan to support people working on
real problems. However, I do plan to make a self-hosting compiler though so I
will have to deal with any issues I do make.

> that authors of such projects seem unable to resist

It definitely is very tempting to add things beyond the scope of a useful
language (at a toy scale). I restricted myself from most such things by
requiring strict C compatibility. You can't have a fancy type system and
interop with C strongly.

~~~
caspper69
> You can't have a fancy type system and interop with C strongly

ATS would disagree with this statement, strongly.

~~~
thethirdone
I haven't used ATS, but I don't think it interops strongly. Hows does calling
a ATS function with fancy typed arguments from C work?

My idea of strong interop is not having to write any glue code at all and
being able to call any function. I assume there are some types that don't
interface with C well.

That said, thanks for mentioning it. I should keep it in mind as it does do
some of the stuff I want my language to.

~~~
TurboHaskal
Grep for "Exporting Types in ATS for Use in C" in [http://ats-
lang.sourceforge.net/DOCUMENT/INT2PROGINATS/HTML/...](http://ats-
lang.sourceforge.net/DOCUMENT/INT2PROGINATS/HTML/INT2PROGINATS-BOOK-
onechunk.html#Cinteraction)

~~~
jcelerier

        typedef
        struct {
           int atslab__0; void *atslab__1; 
        } int_and_string ;
    

very strong typing right there...

------
whitten
Fe is a tiny language with only a few forms ie: if, while, do, define a
variable, define a function, define a macro etc.. It uses an embedded
parenthesis syntax similar to Lisp or Scheme, with prefix functions.

I couldn't see (other than reading the code) if you have an expression (foo
bar quux) if foo is first evaluated before calling the result. I seem to
recall Scheme follows this approach.

Alternately, the name foo could be looked up in a global symbol table and the
result (presumably a lambda expression) is applied to the list of evaluated
arguments (bar quux). I associate this approach with Lisp.

I didn't see any error trapping mentioned in the documentation, so I assume if
you try to do something like divide by zero, that Fe will crash. How much work
does it take to implement a simple error trap strategy ?

I didn't see if the language supports a fluid let (any variable name is looked
up at run time when the reference is encountered thru the stack levels until
the name is found. Presumably each time new variables are created with let,
they would be added at run-time to the symbol table.

The other choice would be that the variables are lexically scoped. Thus when
reading in the code, variables are "found" in the order the program is written
on the page, and there is no searching of the run time stack frames to find
the "innermost" version of the variable name.

From what I can see, Fe is a good language to use if you are happy with the
capabilities the implementor defined initially. There is a set of functions,
named after mathematical operators, like "+", "-", "*" etc. and logical
operators like "AND" "NOT" etc. The doc says these functions take a variable
number of arguments, evaluate them, and then the operator takes each of the
results, and does some operation using them, such as adding them together, or
returning false if any of them are false (AND)

I see nothing in the docs suggesting how a programmer would create his own
functions that function in this way.

It's not clear if the logical operators "short cut" on evaluation of the
arguments. ie: with (or bar quux qide) does the value of quux even get
evaluated if bar is true ?

Is there a short and sweet checklist to help describe a programming language
you have never seen so you know how these types of issues are addressed in the
implementation?

Thanks for sharing your code. I always learn when I read other people's work.

~~~
cryptonector
> I didn't see if the language supports a fluid let (any variable name is
> looked up at run time when the reference is encountered thru the stack
> levels until the name is found. [...]

These are called dynamic variables in Lisp. They're only really useful as a
way of doing things like I/O redirection, and you can just shallow-bind them
to make them fast (but then they need to be per-thread as well, and pushing a
binding requires unwind-protect to pop on unwind).

> The other choice would be that the variables are lexically scoped. [...]

That's what the README says Fe does.

~~~
kazinator
_fluid-let_ is a famous Scheme imitation of dynamic variables.

SRFI-15:
[https://srfi.schemers.org/srfi-15/srfi-15.html](https://srfi.schemers.org/srfi-15/srfi-15.html)
[1999]

~~~
cryptonector
Ahh, ok.

------
fao_
Nice to see another project from you! I remember you from the ludum dare a few
times, but you kind of dropped off the map. Glad that you're still around and
hacking on things :)

------
bigdict
Fe, fi, fo, fum, I smell someone's side project Lisp!

------
kalium_xyz
I smell a lisp

~~~
ngcc_hk
I thought it is ulisp in c

