Hacker News new | past | comments | ask | show | jobs | submit login

But the bespoke language has some benefits. It’s concise and specifically designed for the problem. Also Nix has more contributors and that is very important to have a large collection of recipes to start from.



Scheme, being a Lisp, is exceptionally well-suited to serve as a base for DSLs.


Ok I’ll give another reason. Nix community is more relaxed and doesn’t downvote just because they don’t like some comment or somebody disagrees with them.


I bet you the irony of your downvotes is lost on the people downvoting.


For sure they are pilling on ... for what I don’t get. Relax people.


Do Nix and Guix expressions not interoperate? Is that a fundamental limitation of the system (at lest as fundamental as, say, dpkg and rpm) or could one write a source-level translator?


It's a good question. They don't interoperate now.


Yes, Scheme is a bit verbose for my taste.


There are obviously some differences between the two, but I'm not really perceiving any real verbosity gap between the two, one way or the other.

Here is a guix package declaration for tmux:

[Edit: fixed indentation]

    (define-module (gnu packages tmux)
      #:use-module ((guix licenses) #:prefix license:)
      #:use-module (guix packages)
      #:use-module (guix download)
      #:use-module (guix git-download)
      #:use-module (guix build-system gnu)
      #:use-module (guix build-system trivial)
      #:use-module (gnu packages)
      #:use-module (gnu packages bash)
      #:use-module (gnu packages libevent)
      #:use-module (gnu packages ncurses))
    (define-public tmux
      (package
       (name "tmux")
       (version "3.0a")
       (source (origin
                (method url-fetch)
                (uri (string-append
                      "https://github.com/tmux/tmux/releases/download/"
                      version "/tmux-" version ".tar.gz"))
                (sha256
                 (base32
                  "1fcdbw77nz918f7gqc1ga7zlkp1g112in1h8kkjnkadgnhldzlaa"))))
       (build-system gnu-build-system)
       (inputs
        `(("libevent" ,libevent)
          ("ncurses" ,ncurses)))
       (home-page "https://tmux.github.io/")
       (synopsis "Terminal multiplexer")
       (description
        "tmux is a terminal multiplexer: it enables a number of terminals (or
    windows), each running a separate program, to be created, accessed, and
    controlled from a single screen.  tmux may be detached from a screen and
    continue running in the background, then later reattached.")
       (license license:isc)))

Here is (roughtly) the equivalent in Nix:

    { stdenv, fetchFromGitHub, autoreconfHook, ncurses, libevent, pkgconfig, makeWrapper }:
    
    let
    
      bashCompletion = fetchFromGitHub {
        owner = "imomaliev";
        repo = "tmux-bash-completion";
        rev = "fcda450d452f07d36d2f9f27e7e863ba5241200d";
        sha256 = "092jpkhggjqspmknw7h3icm0154rg21mkhbc71j5bxfmfjdxmya8";
      };
    
    in
    
    stdenv.mkDerivation rec {
      pname = "tmux";
      version = "2.9a";
    
      outputs = [ "out" "man" ];
    
      src = fetchFromGitHub {
        owner = pname;
        repo = pname;
        rev = version;
        sha256 = "040plbgxlz14q5p0p3wapr576jbirwripmsjyq3g1nxh76jh1ipg";
      };
    
      nativeBuildInputs = [ pkgconfig autoreconfHook ];
    
      buildInputs = [ ncurses libevent makeWrapper ];
    
      configureFlags = [
        "--sysconfdir=/etc"
        "--localstatedir=/var"
      ];
    
      postInstall = ''
        mkdir -p $out/share/bash-completion/completions
        cp -v ${bashCompletion}/completions/tmux $out/share/bash-completion/completions/tmux
      '';
    
      meta = {
        homepage = http://tmux.github.io/;
        description = "Terminal multiplexer";
    
        longDescription =
          '' tmux is intended to be a modern, BSD-licensed alternative to programs such as GNU screen. Major features include:
              * A powerful, consistent, well-documented and easily scriptable command interface.
              * A window may be split horizontally and vertically into panes.
              * Panes can be freely moved and resized, or arranged into preset layouts.
              * Support for UTF-8 and 256-colour terminals.
              * Copy and paste with multiple buffers.
              * Interactive menus to select windows, sessions or clients.
              * Change the current window by searching for text in the target.
              * Terminal locking, manually or after a timeout.
              * A clean, easily extended, BSD-licensed codebase, under active development.
          '';
    
        license = stdenv.lib.licenses.bsd3;
    
        platforms = stdenv.lib.platforms.unix;
        maintainers = with stdenv.lib.maintainers; [ thammers fpletz ];
      };
    }


I feel like (inputs `(("libevent" ,libevent) ("ncurses" ,ncurses))) is pretty bad compared to buildInputs = [ ncurses libevent makeWrapper ]; even if you go by token count. (I think it's 16 vs. 8.) A different problem is that syntactically the Scheme version looks like a call to a function called “inputs” and I don't think it is; that depends on context. In general in Lisps the interpretation of everything depends on syntactic context, so you have to do a lot of processing consciously that you can do subconsciously in languages that have a syntax.

(There's an indentation error in either your example or my browser that makes that input clause appear to belong to the origin clause rather than the package clause, btw. The extra redundancy of the different kinds of delimiters makes that error harder to make in Nix. I wrote about this more at length in http://www.paulgraham.com/redund.html )

The module imports at the top are a lot more egregious but that's because they're using Guile’s module system naked; it's not really the fault of Scheme's syntax per se and I think you could hack together some kind of macrological solution.

I think Scheme is brilliant and probably a better choice, but I think the syntactic cost is pretty heavy in your example.

When it comes to Nix and Guix, though, these are kind of minor details. More important questions are things like “does it have the software I want in it” and “how reproducible is it” and “how do I figure out what's broken”.


On the other hand you've got 'stdenv' all over the place in the Nix example, e.g. stdenv.lib.licenses.bsd3 vs license:bsd3. Also stdenv.mkDerivation is kind of an eyesore compared to define-public / package.

One is nicer than the other in a few different minor ways, but overall I think it's basically a wash. I'd not consider verbosity a factor if choosing between the two.

>(There's an indentation error in either your example or my browser that makes that input clause appear to belong to the origin clause rather than the package clause, btw.

Sorry about that, I botched the indentation when I pasted that into my scratch buffer, which had unbalanced parens in it. That's on me.


That sounds like a reasonable point of view.


Those two package descriptions don't appear equivalent. The Nix one includes tmux-bash-completion and some extra build configuration compared to the Guix one, as well as a much more verbose description.


I meant both to be examples of the general look and feel of each DSL. They aren't precisely equivalent, but I do think they're illustrative examples of the two DSLs.


I think the differences are small.


After deleting the bash completion stuff and replacing the verbose description with Guix's, it cut the package from 63 lines down to 36. Deleting the blank lines cut it down to a further 27. For comparison the Guix package (which had no blank lines to begin with) is 35 lines.

Here's the trimmed Nix derivation:

  { stdenv, fetchFromGitHub, autoreconfHook, ncurses, libevent, pkgconfig, makeWrapper }:
  stdenv.mkDerivation rec {
    pname = "tmux";
    version = "2.9a";
    outputs = [ "out" "man" ];
    src = fetchFromGitHub {
      owner = pname;
      repo = pname;
      rev = version;
      sha256 = "040plbgxlz14q5p0p3wapr576jbirwripmsjyq3g1nxh76jh1ipg";
    };
    nativeBuildInputs = [ pkgconfig autoreconfHook ];
    buildInputs = [ ncurses libevent makeWrapper ];
    meta = {
      homepage = http://tmux.github.io/;
      description = "Terminal multiplexer";
      longDescription =
        '' tmux is a terminal multiplexer: it enables a number of terminals (or
  windows), each running a separate program, to be created, accessed, and
  controlled from a single screen.  tmux may be detached from a screen and
  continue running in the background, then later reattached.
        '';
      license = stdenv.lib.licenses.bsd3;
      platforms = stdenv.lib.platforms.unix;
      maintainers = with stdenv.lib.maintainers; [ thammers fpletz ];
    };
  }


Nice! I find this a lot more readable than the Scheme, and it certainly contains many fewer tokens; what do you think?


That looks almost identical to the Scheme one with the only real difference being foo=bar; vs (foo bar). Hardly enough of a difference to change anything "a lot" either way.


Guix package definitions were unreadable to me initially, as I had never used Scheme/Lisp before.

I've written a couple of them now and the definition above is extremely easy to read. Big part is just formatting & parentheses, I think my eyes just needed a little bit of adjustment time.


It’s absolutely more readable.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: