Gauche Devlog

2015/08/07

Write control variables

Oh well. More than a year since the last entry. So many things has loaded into HEAD and I have to wrap it up as 0.9.5. Some small issues to address, though.

As a part of improving REPL experience, I implemented CL-like write control variables. Those like *print-length*. In Gauche it looks like a parameter.

gosh> (parameterize ((print-length 5)) (write (iota 10)))
(0 1 2 3 4 ...)#<undef>

I wanted them every time I accidentally evaluated huge data structure on REPL and just waited Emacs to finish showing it until the end (Ctrl-C can stop Gauche printing it, but it's mostly Emacs that's taking time to fill the buffer, especially when font-lock mode is on.)

By the way, print-base comes handy as desktop calculator for base conversion:

gosh> (print-base 16)
a
gosh> (print-radix #t)
#f
gosh> 4758375874
#x11b9f0dc2

Now I've implemented four of various CL's printer control variables, and sit back and am thinking. Are they really useful as they seem to be?

The global nature of those controls is the problem. I'd like to limit print-length on REPL output to avoid excessive output. But doing so globally affects every operation, such as serialization to file or network connection, which is almost certainly undesirable. I can create a custom printer for REPL that changes the controls only when it prints the result, but then I need another set of API to set those values REPL would use.

Worse, now every routine that writes out values expecting it to be read back must be wrapped with parameterize to ensure those control variables are in the default value, otherwise it can be broken accidentally when called with print-level set to 5.

The more I think, the more dubious I became about the CL's choice of making them dynamic variables.

Another idea I had before is to have a "context" object that packages those controls, and you can set it to a parameter, instead of parameterizing individual controls (the name ScmWriteContext in the source was somewhat intended for that, but ended up for different purpose.) With that, the REPL can have just one repl-default-context and use that for just printing.

Recently I got yet another idea; let a port have those controls. We already have port-attributes to associate key-value pairs to ports. For serialization you'll usually create a fresh ports so the chance of inadvertent interference is very low. For REPL output, we can create a wrapper port connected to stdout so that it can have separate attributes, and use it for printing the results.

Some more pondering.

Tags: REPL, 0.9.5

2014/07/20

Oops - gauche-package regression

Alert for those who start writing new extention package with Gauche 0.9.4. When you create the skeleton files by gauche-package generate, you need to tweak the generated files to make them work.

Before going into details, I just describe what to do:

After generating skeleton files, edit configure script to add the following stuff right after ;; Output line:

(use gauche.package)
(let1 gpd-file #"~(cf$ 'PACKAGE_NAME).gpd"
  (with-output-to-file gpd-file
    (cut write-gauche-package-description
      (make <gauche-package-description>
        :name (cf$ 'PACKAGE_NAME)
        :version (cf$ 'PACKAGE_VERSION)
        :configure (string-join (command-line))))))

And in Makefile.in, remove configure from the rule of maintainer-clean target, as shown in this patch.

  maintainer-clean : clean
-       rm -rf $(CONFIG_GENERATED) configure VERSION
+       rm -rf $(CONFIG_GENERATED) VERSION

Now, the explanation.

0.9.4 is shipped with new gauche.configure module, which attempts to replace autoconf-based configuration to build Gauche extensions.

Autoconf is well-built system, but it makes great effort to make configure scripts work on a minimal environment. In order to do so, it requires an extra step for developers to generate configure script from configure.ac etc. It is reasonable for distributing basic tools to the destination platform that lacks them.

However, when installing Gauche extensions, we know for sure that the destination platform already have Gauche installed, so the configure script doesn't need to be restricted in the minimal shell features. In fact, we can write configure script itself as a Gauche script, eliminating the step for developers to generate configure script from other files.

Nowadays more and more projects don't bother to create distribution tarballs and ask users to just pull from repository. Making configure script a source, not something to be generated, has advantage for not requiring users to run autoconf.

So I migrated the default skeleton files to use new configure features. But I forgot to cover a couple of points, as shown above.

The .gpd file is to keep metadata of the extension package. In the old skeleton configure.ac file, it is generated by calling gauche-package make-gpd. My plan is to provide an easier API in gauche.configure, which will be in the next version of Gauche.

And of course, we no longer need to remove configure in maintainer-clean!

Autoconf has comprehensive feature tests gauche.configure can't match. If you need advanced feature tests, you may still want to use autoconf-based configuration. Just give --autoconf option to gauche-package generate, and it gives you configure.ac.

gauche-package generate --autoconf YOUR-PACKAGE-NAME

Tags: 0.9.4, Extension, gauche-package

2014/07/20

0.9.4 is out!

Thanks for those who tested release candidates.

Tarball:

Windows installer (including Gauche-gl):

Release notes:

Tags: Gauche, r7rs

2014/05/03

Keyword-symbol integration

Aargh, Already May? Unbelievable. Final stretch turned out to be a long marathon.

If you monitor github repo https://github.com/shirok/Gauche you know it's actively developed, though most changes are minor fixes. I cleared the items on the table I listed last time for 0.9.4 release, but I realized I left out one major item: Keywords.

Gauche has a keyword type, disjoint from other types. I think I inherited it from STk. I also speak Common Lisp and having :keyword is so natural that I tend to forget that treating keywords specially actually conflicts RnRS spec. In RnRS, they must be symbols.

In fact, it became an issue when we adopted srfi:42, in which symbols beginning with : is used. Alex Shinn employed a clever trick during macro expansion to work around the issue.

Now, with more R7RS libraries coming out, I expect this design would be a bigger obstacle.

Some implementations that have keywords avoid this conflict by adopting a syntax different from symbols, e.g. #:keyword. In fact, my original plan was to make the keyword syntax customizable, :keyword, #:keyword or even keyword: (DSSSL style; anybody remember?). That's why we don't have the colon in keyword's name slot. However, mixing these syntax is just confusing, and I strongly prefer :keyword anyway. #:keyword has a merit of not conflicting with symbols, but they are visually too intrusive, and it has been used as uninterned symbols in CL and Gauche.

Technically we don't need to make keywords separate from symbols; indeed, in CL, keywords are just symbols in the keyword package. We can just do the same:

  • We can make <keyword> a subtype of <symbol>. Identifiers beginning with ':' are read as an instance of <keyword>, but they're also symbols. So keyword? still works, but keywords also return #t for symbol?.
  • We can have gauche.keyword module, that acts as if it has constant bindings of every possible keywords, bound to itself. In reality, we create such bindings on the fly as keywords are read.
  • Then the gauche module can inherit gauche.keyword, so that existing usage of Gauche keywords will be preserved. They are symbols, but evaluate to themselves. It also allows programmers to rebind keywords (locally or at the toplevel of their modules) but the effect stays local, and those who conduct such an act should know what they are doing.
  • The r7rs module does not inherit gauche.keyword, hence symbols starting with : are just ordinary symbols. All portable R7RS code should run.
  • If one wish to use Gauche features and import gauche.core, the bindings of those keywords come with it, so you can call Gauche procedures with keyword arguments just like you're using Gauche.

This looks reasonable to me. There are a couple of catches, but I think they are minor and easily worked around:

  • If you import some of Gauche's procedures into R7RS code by (import (only (gauche core) foo ...)), keywords are not imported, so you should call it something like (foo ':bar b ...) i.e. quoting keywords.
  • If you import both an R7RS library that exports bindings of symbols that begins with : and gauche.core into R7RS code, whichever comes later would shadow the former. Generally you need to import gauche.core first.

However, this change needs to break the backward compatibility of certain cases, and it turned out it's a bit complicated. I'll describe it later.

Tags: r7rs, keyword

2014/02/07

Almost there?

Just committed changes to cover R7RS-small support.

  • Exact complex numbers are not in yet. In next version, I hope.
  • Problems have been reported regarding hygienic macro-defining macros (Macros that expands to let-syntax). It's a long-standing issue, but I'm going to give one more try before releasing 0.9.4. If it turns out a lot of work to fix, though, I'll postpone it to the next version.
  • Currently, toplevel import is Gauche's by default, which is different from R7RS import. So you need -r7 option for gosh to run R7RS scripts. However, as R7RS gets adopted more widely, users would expect R7RS code just works on Gauche, so requiring -r7 option may confuse them.
    I can't change Gauche's import semantics for the backward compatibility, and I don't want to extend Gauche's import to support R7RS semantics, since those two have different functions (R7RS import ≒ Gauche's userequire + Gauche's import).
    However, I had another idea. The import issue only arises when a Scheme script uses it on toplevel. When a Scheme script is given, gosh start evaluating it in user module. So we can provide the third import form in user module, which checks its arguments and dispatch to either R7RS import or Gauche import.
  • And of course, I need to go through documents to update for R7RS.

Tags: r7rs, 0.9.4

More entries ...