6 comments

  • as-j 1481 days ago
    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 1481 days ago
      > 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

    • cryptonector 1481 days ago
      > 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?

      Ever look at Chicken Scheme? It uses the stack as a heap, and its functions never unwind the stack to return. Hitting the stack size limit triggers a copy garbage collection that resets the stack.

      I imagine Fe has a similar design.

      Allocation is super fast in the Chicken Scheme way, and GC is, well, GC, and you don't have fragmentation to worry about.

  • dccoolgai 1481 days ago
    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 1481 days ago
      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 1481 days ago
        > You can't have a fancy type system and interop with C strongly

        ATS would disagree with this statement, strongly.

        • thethirdone 1481 days ago
          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 1481 days ago
            Grep for "Exporting Types in ATS for Use in C" in http://ats-lang.sourceforge.net/DOCUMENT/INT2PROGINATS/HTML/...
            • jcelerier 1481 days ago

                  typedef
                  struct {
                     int atslab__0; void *atslab__1; 
                  } int_and_string ;
              
              very strong typing right there...
          • caspper69 1481 days ago
            I apologize for being ambiguous. You wouldn't gain the benefits of ATS by interfacing with its C bindings from C. You would gain safety and security in interfacing with unsafe C on the ATS side through the ATS type system.

            I was speaking about interfacing in the opposite direction.

            • thethirdone 1481 days ago
              > I apologize for being ambiguous.

              No need to apologize. I also should have been more clear about what I meant by strong interoperability.

              > I was speaking about interfacing in the opposite direction.

              I think that having really strong interoperability requires both directions, but the being called from C is the one that is more restrictive on fancy types.

              • caspper69 1480 days ago
                Unfortunately, C is C, and we all know what that means. Anything that achieves true type safety in both directions in going to be a monstrosity on the C side. Lots of boilerplate, marshalling of types, etc.

                It all starts to look like COM, lol. Take care man.

        • tzjmetron 1481 days ago
          Please don't make me relive nightmares of trying to learn the language.
  • whitten 1481 days ago
    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 1481 days ago
      > 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.

  • fao_ 1481 days ago
    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 1481 days ago
    Fe, fi, fo, fum, I smell someone's side project Lisp!
  • kalium_xyz 1481 days ago
    I smell a lisp
    • ngcc_hk 1481 days ago
      I thought it is ulisp in c