Hacker News new | past | comments | ask | show | jobs | submit | middayc's comments login

Uh ... BrianH and Ladislav ... two of the real Rebol magicians. I can't wait to read the second again, and the first for the first time!

Hehe, thanks ... I didn't know if anyone would find it at least a little funny ... or weird :)

There is a whole thread about Tcl/Tk a little lower that you might find interesting (https://news.ycombinator.com/item?id=41634817). I can't comment on what is more readable, as I am not proficient in Tcl. I intend to look at it now that it keeps getting mentioned. Tnx.

Rebol has something named definitional scoping. Interesting document about that was called "bindology" (If I remember correctly).

We don't have a tutorial about this. In Rye this is still partially open to experimentation. If in Rebol dialects were the most interesting part. Rye also has multiple dialects, but I think in Rye contexts (scopes) are the most interesting aspect of the language.

In very short. Code is always evaluated inside a specific context. This also determines what certain words mean (from "core" words, like if, for, fn, ... up). Contexts can be linked together (you can define a parent context), created, manipulated, isolated at runtime. We have functions like do\in do\par(ent) and also fn\in and fn\par that evaluate code in context you provide. Lookup for a word happens in current context and then if not found in it's parent contexts if there are any. This is lookup ... "read" operation, but you can change (set or mod) only words in a current context. There is no syntax to change a value in parent or sub-context (there is no global context). You can call functions in (send messages to) contexts in your view and convention is if functions change values in-place their name must end with !.

That is current idea in very short, but this is all still open to be tested in practice and potentially changed.


Hm ... I keep hearing about tcl and I'm aware Rebol and Tcl have some similarities, but I've never really looked that deep into it. Now I looked at the first example that I found (https://wiki.tcl-lang.org/page/A+little+stopwatch) and visually there really are many similarities. We also seem to use the same word-formatting combinations. I see ".word" "::word" { } and [ ] blocks. They are all probably used for different things, but it is funny. I really need to look at Tcl at some point.

I was a little discouraged by "everything is a string" idea so far, but I keep hearing that it is conceptually very interesting language.


'everything is a string' is a fatal flaw in tcl, both in terms of bugproneness and performance. it does have some real advantages, though: serialization for storage, configuration, debugging, or networking is trivial, and it eliminates aliasing bugs, especially important for end-user programming

independent of 'everything is a string', tcl also works much better as a command language than 'real programming languages' do; contrast

    ifup eth0 -ip 192.168.2.53
with

    ifup('eth0', ip='192.168.2.53')
which is a real pain to type when you're in a hurry. but you could get that benefit by only making things strings by default; requiring [] or $ to get expression evaluation is conceptually independent of tcl's type system or lack thereof

the rebol family seems like an improvement over conventional programming languages there, but at the cost of conceptual simplicity

wrt guis in particular the ability to edit the gui without restarting it is pretty great. but this is a suboptimal way to edit it:

    .qd.ipentry configure -textvariable ip
on the other hand, the ability to trigger code when a variable changes is pretty awesome

(edited to clarify)


Interesting example. Now I maybe understand a little what is meant with everything being a string. Before, I didn't quite know the catch.

Rebol went the opposite way for somewhat similar effect. It famously had (I think) 37 datatypes and a lot of them were also syntax types, like email, url, IP also I think. So your example could be something like this in Rebol:

    ifup/ip 'eth0 192.168.2.53
In Rye it's similar.

"everything is a string" hasn't been a serious performance issue since the release of Tcl 8.0 decades ago. I've written large, successful applications in Tcl/Tk.

Granted, programming in the large in Tcl requires discipline and a good set of tools. (I used the Snit object framework, with SQLite as a data store.)

As for command languages: yes, this is where Tcl really shines; nothing else is as good.


tcl 8.6.13 still has serious performance problems, although indeed 8.0 did improve the situation dramatically; it's on the order of 64× slower than native code in simple microbenchmarks like http://canonical.org/~kragen/sw/dev3/dumbfib.tcl, which also means about 2× slower than cpython. its type system is a big part of the reason why

compare†:

    : ~; time tclsh <<<'proc fib {n} { if {$n < 2} {return 1} else {return [expr {[fib [expr {$n - 1}]] + [fib [expr {$n - 2}]]}]}}; puts [fib 35]'
    14930352

    real 0m8.351s
    user 0m8.346s
    sys 0m0.004s

    : ~; time luajit -e 'function fib(n) if n < 2 then return 1 else return fib(n-1) + fib(n-2) end end print(fib(35))'
    14930352

    real 0m0.127s
    user 0m0.122s
    sys 0m0.004s
even with the huge performance hacks added in tcl 8.0, it's only about 64 times faster than bash

    : ~; time bash -c 'fib() { if [[ $1 -lt 2 ]]; then result=1; else local arg=$1; fib $(($arg - 1)); local tmp=$result; fib $(($arg - 2)); result=$(($tmp + $result)); fi; }; fib 35; echo "$result"'
    14930352

    real 8m24.591s
    user 8m24.412s
    sys 0m0.028s
which puts it about halfway in between shell scripts and native code

that doesn't mean you can't write large, successful applications in tcl, even without any c extensions! a core i7 is about 17000 dhrystone vax mips http://www.roylongbottom.org.uk/dhrystone%20results.htm while a pentium 166 was about 270 mips. so anything you could do with usable performance on a pentium you can do, with enough discipline, in pure tcl. it'll probably be a lot quicker to write than pentium assembly, too. and things like arrays (hash tables), regular expressions, sqlite, tk, etc., are of course enormously faster on a current computer, and you have a thousand times as much ram to play with and probably an ssd

but you probably don't want to write your fractal renderer or real-time raytracer in tcl. by contrast, i've done both of those successfully in lua with luajit: https://gitlab.com/kragen/bubbleos/blob/master/yeso/mand.lua https://gitlab.com/kragen/bubbleos/-/blob/master/yeso/sdf.lu...

in terms of command languages, what do you recommend for getting good tab-completion in tcl? i don't know of any good options but that doesn't mean there aren't any; it probably just means i'm ignorant

______

†before wduquette's very helpful correction, I had:

    : ~; time tclsh <<<'proc fib {n} { if {$n < 2} {return 1} else {return [expr [fib [expr $n - 1]] + [fib [expr $n - 2]]]}}; puts [fib 35]'
    14930352

    real 0m59.757s
    user 0m59.736s
    sys 0m0.004s
and while, in some sense, maybe my additional 8× slowdown here was kind of a performance effect of the everything-is-a-string type system, it's not an unavoidable one

You can speed that Tcl snippet up considerably by putting braces around the expressions, e.g., `expr {$n - 1}`. On my system it went from ~22 seconds to ~4 seconds.

Without the braces, the expression gets parsed twice, once as Tcl syntax and once as Tcl `expr` syntax. Luajit is still going to be faster, but Tcl will do better than what you're showing there. (Not bracing expressions is the most common reason by why Tcl code runs slowly.)

In terms of tab-completion, you have to roll your own; and if you're trying to do it in the console, you're going to need to write your own REPL: the standard `tclsh` doesn't even have "readline" editing.

Back when I was doing Tcl regularly, I wrote a Tk "terminal" widget, and all my Tcl/Tk apps had a way to pop it up. Made life much easier.


hey, thanks! i should have known that and didn't. i've corrected my comment above since you corrected me so quickly that i could still edit it!

i feel like readline and tab-completion is pretty important to a good command language, and plausibly you want to integrate support for tab-completion into the design of the language itself rather than having to write a separate completer for each command

i'm kind of puzzled why tclsh doesn't have any command-line editing. maybe ousterhout's team was only ever using tclsh in emacs shell-mode or something like your tk terminal? as an exercise, i wrote a basic command-line editor in c in bed on my cellphone the other night. it took me an hour and a half and 120 lines of code (with a very narrow line length to fit onto the cellphone screen), and it supports arrow keys, movement by words, word delete, about a dozen keystroke commands in all, which is most of the ones i use. (though i really need to fix the cbreak handling and handling of wide lines to work reliably.)

http://canonical.org/~kragen/sw/dev3/editline.c

tcl is about 200'000 lines of c; there's no reason for tclsh to be missing this


Historically it’s because TCL uses the BSD license and GNU readline does not. But yeah, no reason not to implement an alternative.

As for speed, it’s less that everything is a string (internally, data gets stored as both a string and whatever it last needed to be converted to) and more because TCL is so dynamic that compiling it is hard.

There’s been some work on compiling to native though.


i can see how upvar and uplevel could be a problem for compilation

upvar and uplevel are a significant barrier to optimisation, but not to plain compilation — the hardest part would be autovivification of fresh up-locals, and even that sounds like an extra indirection could reasonably handle it?

EDIT: looks like tcl doesn't bytecode uplevel expressions, so I must be missing a catch?


yeah, what i was thinking of specifically was that they would be a major barrier to optimization, which is the benefit one hopes for from compilation

to be specific, it would be pretty hard to optimize a non-leaf procedure if any other procedure it called were able to violate any assumptions you'd made when optimizing it. elided redundant type checks, perhaps to specialize a proc? the proc it called changed the type of one of its variables. constant propagation? that proc changed the value of the variable you thought was constant. strength-reduction? likewise. you aren't going to get much dead code elimination without constant propagation. invariant hoisting? how are you going to figure out what's invariant if a proc you're calling inside the loop could change any of the variables used in it? register allocation? better have a way for upvar and uplevel to look up which register it was


> 'everything is a string' is a fatal flaw in tcl, both in terms of bugproneness and performance

Also security I suppose. I'm thinking of injection attacks.


tcl's string interpolation semantics are much, much better than unix shell semantics, and i don't remember having seen a tcl string interpolation vulnerability along the lines of shell injection attacks and sql injection attacks and xss. still, it does seem like something to watch out for

Yes, Rye started and is basically Rebol + few more word types (Rebol has multiple types of words) that allow left to right oriented evaluation (op-words, pipe-words, left-set-words).

Get words are `?word` instead of Rebol's `:word` because that's left-set-word, we don't have refinements and scoping / contexts work somewhat differently. There are probably other differences in details, but all basic concepts are based on Rebol.


It's nice; well done.

Rye works on web too, we are currently trying to make a proper and fully compatible web console (REPL) and then include more web technologies. So I think there should be no problem in running Rye-Fyne on web. In fact the developer who is working on binding generator proposed it few chats ago.

What exactly do you mean by LiveView?


Like Phoenix Liveview [0], so frontend/backend blurs and you don't have to think about what is front and what is backend; everything is backend and parts of the frontend are updated based on serverside DOM changes. No JS; such a blessing.

[0] https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html


I was so far a little skeptical of these all-in-one solutions, but never say never and language is general one, so somebody could try to tackle this if they see the oportunity. I will try to find out more about LiveView, thanks for the link.

I was as well, but in the last years they really jumped ahead; it might be personal, but for me I cannot imagine going back. Especially when I now use nextjs or so, I scratch my eyes out. It's such an timewasting and frankly annoying experience compared to liveview, livewire [0], go live [1] and of course CLOG [2].

Edit; Blazor server[3] is another one

[0] https://laravel-livewire.com [1] https://github.com/jfyne/live [2] https://github.com/rabbibotton/clog [3] https://learn.microsoft.com/en-us/aspnet/core/blazor/hosting...


Thanks for pointing it out. Frankly I haven't looked at that topic with Fyne yet. If I google it I see this response from the main Fyne maintainer from 2022:

https://news.ycombinator.com/item?id=31788824

They do keep actively moving forward so I have hope this will get addressed.


Accessibility was mentioned at FyneConf last week as a priority. It may not make it to v2.6.0 this year but expect it in 2.7. https://conf.fyne.io

Great to hear. I have yet to see the full video of the conf. (It's on Youtube)

On that thread, I plugged my AccessKit project (https://accesskit.dev/). We have a C API now, and the project is much further along than when I commented on that old thread, so somebody could develop Go bindings now.

What an excellent project and idea. Accessibility is always a big gap in these cross-platform, lowest common denominator frameworks, glad to see someone is trying to tackle it.

Thanks for the feedback. Good idea. I will make "Go's Fyne UI library bold" and provide a link to Fyne page at the top.

Looking at the first example from PDF:

    FROM customer
    |> LEFT OUTER JOIN orders ON c_custkey = o_custkey
    AND o_comment NOT LIKE '%unusual%packages%'
    |> AGGREGATE COUNT(o_orderkey) c_count
    GROUP BY c_custkey
    |> AGGREGATE COUNT(*) AS custdist
    GROUP BY c_count
    |> ORDER BY custdist DESC, c_count DESC;
You could do something similar with Ryelang's spreadsheet datatype:

    customers: load\csv %customers.csv
    orders: load\csv %orders.csv

    orders .where-not-contains 'o_comment "unusual packages" 
    |left-join customers 'o_custkey 'c_custkey
    |group-by 'c_custkey { 'c_custkey count }
    |group-by 'c_custkey_count { 'c_custkey_count count }
    |order-by 'c_custkey_count_count 'descending
Looking at this, maybe we should add an option to name the new aggregate column (now they get named automatically) in group-by function because c_custkey_count_count is not that elegant for example.


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

Search: