[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: printf is a crappy language in a crappy language (was Re: [OT] Lua community and Go language)
- From: Jay Carlson <nop@...>
- Date: Tue, 13 Aug 2013 02:18:43 -0400
On Aug 8, 2013, at 9:37 AM, steve donovan wrote:
> On Thu, Aug 8, 2013 at 3:20 PM, Lorenzo Donati <lorenzodonatibz@tiscali.it> wrote:
>> fmt.Println(time.Now().Format("2006-01-02 03:04"))
> It is very .. eccentric. Rob Pike is very proud of this idea ;)
It is a cute idea, but just like printf, it's a symptom of a lack of expressive power at compile-time.
Famously, the Pascal runtime cannot be implemented in terms of itself. C is much better, but originally had no standard mechanism for functions with a variable number of arguments either; there was no way of writing your own printf.
An informal mechanism and then a standard were created, and they're designed to barely handle printf/scanf, and forwarding of those varargs.
Most C compilers these days have special mechanisms hooked up to the printf/scanf functions to warn of mismatches in type between the format string and the arguments. So there's a special case again: you can't write your own replacements with the same functionality, especially if you are in the -Werror camp, where warnings are treated as errors.
What time.Format and printf/scanf have in common is that they use raw strings as little languages compiled and evaluated at runtime. Why strings? Because other kinds of literals are too painful to express, usually. Here's some fake Go code:
import "time"
import . "time/format" // hate-magnet[1]
ISO8601 = TimeFormat{YYYY, MM, DD, Lit{"T"}, HH, Lit{":"}, MS, Lit{":"}, SS}
Kitchen = TimeFormat{Hh12, Lit{":"}, MS, PM}
RFCTime = TimeFormat{HH, Lit{":"}, MS, Lit{":"}, SS, Lit{" "}, TMZ}
// Tired of retyping stuff?
s_ = Lit{" "}
RFC1123 = TimeFormat{Wkday, Lit{", "}, DD, s_, Mon, s_, YYYY, s_, RFCTime}
Where various YYYY types as well as TimeFormat itself all implement a common formatting interface.
I don't know about you, but in this case I think expressing structure as structs seems a lot more painful than just chucking everything into a string. Which is too bad, since I already had enough "everything is a very weakly typed string" in my Tcl years. Aren't these higher level languages supposed to be higher level?
For Lua, the safest thing is to compile the specs at module load time:
local RFCTime = TimeFormatter"HH:MS:SS TMZ"
function yow()
if rarely_taken_conditional then
io.write("Yow! It's ", RFCTime(os.time()), ".")
end
end
which means you'll find out you screwed up your MM/MS/MN syntax *before* rarely_taken_conditional becomes true.
But for composition you need something like this:
local RFC1123 = TimeFormatter$"Wkday, DD Mon YYYY $RFCTime"
where $"" is syntactic sugar of the general form
$"abc $foo def" => {"abc $foo def", foo=foo}
to be able to work in the lexical environment.
Jay
[1]: This is one of those times for a block scope for those "import * from blargh" statements.. All symbols from blargh would become first in lookup order in some limited spot, without spraying the rest of your code with them. _ENV is very nice....