Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
ParTcl – a micro Tcl implementation (github.com/zserge)
79 points by panic on Feb 18, 2017 | hide | past | favorite | 31 comments


Pretty neat that it was implemented in less than 600 lines of C.

One drawback, though, is that you couldn't use it for arbitrary data. The strings seem to be mapped to C strings, so variables can't contain nulls. No way to express a null in a string literal, either.

Edit: antirez (redis creator) also made a tiny tcl interpreter...actually a little smaller than Partcl. Has the same issues with null chars: http://oldblog.antirez.com/post/picol.html


When I made partcl, I also wrote a brief post of why+how I implemented it: http://zserge.com/blog/tcl-interpreter.html I tried to keep data representation separate from the main interpreter code, so if one needs to use binary data or real lists - he may only rewrite a small part of code.


Well you could always do something like base64, which might be a fine work-around in some situations.


I mentioned it mostly because the actual tcl interpreter originally had this issue. When it was fixed, the language became much more useful.

Base64 wouldn't help much dealing with existing binary files, for example. Or network protocols, or unicode, and so forth.


If fixed properly, it would open the door to non-string types - like, you could have a type that's entirely opaque to tcl, just a void * or whatever, accessed only through functions. This might even actually end up being a step up compared to "proper" tcl...

This would push the line count over 600, but I bet it would still come in at less than a nice round 1,000, while making the thing a lot more useful.

(I have a side project that's starting to feel like it might need a scripting language. And I always liked tcl. Must... resist... rabbit holes...)


Probably a rabbit hole, but tcl strings are sort of dual typed.

Normally, they are arrays of unicode, including multibyte.

But tcl offers a keyword "binary" to treat them as arrays of single bytes.

http://wiki.tcl.tk/1181


Not the first project to go for the "particle" pun ;) https://github.com/partcl/partcl


Ah, Parrot VM. Brings flashbacks of the dynamic typing bubble.

No offense unitypers, maybe your typing systems have valid use-cases, I'm not sure. I'd like you to convince me if possible.

EDIT: Using slightly less off-putting language. I truly welcome arguments, even sound opinions.


> dynamic typing bubble

Could you explain this? I'm not aware of such a thing at all?

> maybe your typing systems have valid use-cases,

I'd like to ask before I start explaining, what is your current level of knowledge on different kinds of dynamically typed languages? It's hard to say from your comment alone[1]. Have you ever worked with a Smalltalk or Lisp live environments? Have you ever used Assembly or Forth? Are you aware of Erlang's Dialyzer or Racket support for contracts?

There are many ways to do dynamic typing, and they vary widely in both their aims and methods. It's important to note, however, that most dynamic type systems arise from a severe failure of static typing. As long as there are useful programs which would be rejected by a type checker dynamic typing will remain in use.

[1] I'm trying really hard to apply 'principle of charity' here.


The popularity of dynamic typing, I think, was at its peak around 2010, mostly due to the purported rediscovery of the "good parts" of the only client-side language for the web, the unprecedented acceptance of Python by academia, and the popularity of Ruby on r..the web (but PHP as well). Around the time that asm.js started being discussed, however, the trend was reversed: Though it may have made the benefits of static typing obvious, need for speed wasn't what replaced the likes of CoffeeScript with the likes of TypeScript. As web applications became more complex, the old Large Systems called for safety guarantees. Industrial languages never even considered losing their types, while improving considerably by adopting functional concepts. Nowadays I see no notable arguments for dynamically typed programming languages. With the exception Fowler's 2005 testing argument being reiterated, static typing is no longer being challenged. The new kids: Go, Rust, Swift - they all indicate that the errors will not be left to the runtime (or the unit test). It seems to me that the advocacy has been reduced to voicing personal preferences. I may still provoke the bold claim of there being "severe failure of static typing", but without any arguments, the default today is going to be to discount the claim, on account of the probability that it has merits that outweigh type safety alone.

I have only used a JS live environment (the browser console) but I hope you have in mind something that my static language's debugger cannot do. I assume the next two languages are about reflection - I've done some. Finally, I'm unfamiliar with the Erlang's static analysis tool and I don't know Racket's contracts, but I'd like you to tell me how they differ and why you think they're better than my own.


> As web applications became more complex, the old Large Systems called for safety guarantees.

I.e. "we can't possibly test the cases occurring in this mountain of code, so let's make it type check, and if it's clean, let's call it correct and ship it".


I wonder if this is a generational thing. Learning programming in the 1980s with Pascal, static typing was just seen as a fact of life. When I discovered dynamic typing/scripting languages in the 1990s it was a revelation -- it made programming much more productive and perhaps equally as important, fun.

The current generation grew up on scripting languages and now this current return of static typing is seen as something new and exciting rather than a return to the old days. Computing has recurrent ideas/fads. In the 1970s/1980s, a popular strain of Pascal was UCSD Pascal, which ran on a virtual machine (the p-machine). People realized that this was inefficient and moved to native binaries. Kind of what's happening now with JVM and .NET as the new wave of programming languages make native binaries again.


> With the exception Fowler's 2005 testing argument being reiterated

Besides testing, dynamic languages can also be good for glue code, or scripts for builds. Just don't use them to write systems. Of course, when a script starts becoming a system is vaguely defined. I think the best way is to always be ready to pull some logic out of a script into its own system whenever a script starts getting too big.


> It seems to me that the advocacy has been reduced to voicing personal preferences.

It was like this from the beginning.

Almost all arguments about type systems center around how "useful" the type system is. This is obviously a problem: the usefulness is a subjective notion! Two people with different preferences (and/or in different circumstances) may disagree about how useful some particular type system is - and they could be both right, at least for their use cases.

This makes the discussion hard and tiring.

For dynamic typing people, static type systems are limitations which need to be subverted before they can code using their preferred techniques. For static typing people, types are tools which allow them to code the way they like. It's entirely subjective matter.

In effect, it is almost impossible to "convince" people without first broadening their technique sets. There is literally no good argument for the other typing kind if you continue writing code dependent on the previous typing scheme.

And when you master techniques from both sides you tend to realize the subjectivity and become disinterested in the topic, which doesn't help the quality of the discussion...

> Nowadays I see no notable arguments for dynamically typed programming languages.

A quick Google brought up an article from Dec 2016: https://medium.com/javascript-scene/you-might-not-need-types...

> The new kids: Go, Rust, Swift

What about Elixir and Clojure? Not to mention, the dominant platforms (JVM, CLR) getting better support for dynamic languages?

> I may still provoke the bold claim of there being "severe failure of static typing."

I think you interpreted my statement too broadly. What I said was that dynamic typing systems are being created in response to a particular (class of) programs which are correct, yet rejected by the static type checker. Such rejection is viewed as a "failure" of static typing, that's all.

> I hope you have in mind something that my static language's debugger cannot do.

No. There's nothing you can do in one language and definitely cannot in another, as long as the languages are both Turing-complete. You can write an interpreter for a dynamically typed language in a statically typed one and a statically typed language preprocessor (type checker) in a dynamically typed one.

I mentioned Racket contracts because of the research and work that went into a statically typed dialect of Racket, the TypedRacket language. One of the goals of the project was seamless interop with dynamically typed Racket while providing the safety guarantees in both worlds. This resulted in the automatic generation of contracts out of types. This is an impressive example of an argument for dynamic and static type systems equivalence.

I mentioned Dialyzer because of the notion of "success typing". Dialyzer is a static type checker, which only rejects programs it knows for sure will result in error. Traditional type systems require the programmer to supply the proof that the code is correct and will refuse to type check without one. Dialyzer is optional, meaning you can provide the types or not and it will accommodate. It gives many of the advantages of static typing without being a pain.

I mentioned Forth and Assembly because these are the only languages I know of (TCL may also qualify) which are truly unityped. I suppose you'd like dynamic typing more after working with something which lacks any kind of types.

I mentioned live environments of Smalltalk and Lisp because they provide the tools which rival (and, frankly, beat) the tooling enabled by static type systems. These environments are designed to be always running, you load your code and changes into the running image. Combined with reflection and introspection, it allows for the most accurate auto-complete you've ever seen: at any point, you know exactly which classes have which methods. The refactoring tools of Smalltalk are legendary and are possible only because the code itself is a part the running image and may be queried and changed programmatically (at run-time). Gilad Braha has some good talks on the advantages of a live environment over a static one.

Well, in any case, you shouldn't wait to "get convinced" by someone. You should try to learn the dynamic typing side of things on your own and use it for a while. It will make you a better programmer overall, even if you get back to static typing later.


Note that even Tcl had a recent proposal to support optional type annotations, but for run-time efficiency reasons rather than compile-time checking - http://code.activestate.com/lists/tcl-core/17707/


I recognize that we can have different goals, and you may value flexibility over safety. However, it is not a matter of opinion whether software safety (and therefor availability) benefits from checks performed before run-time. Conversely, it is not a matter of opinion that dynamic languages allow patterns that static typing does not (eg. duck typing[sic]). These are objective arguments we can discuss, and weigh against each other. There are even studies that we can throw in here.

>> Nowadays I see no notable arguments for dynamically typed programming languages. >A quick Google brought up an article from Dec 2016: https://medium.com/javascript-scene/you-might-not-need-types....

I glanced over it the other day and wasn't very interested. I wanted to give it a more thorough look before I replied to you, but it seems it got pulled. looks meaningfully

>What about Elixir and Clojure?

I see your Erlang dialect Elixir with Elm (arguably a dialect of ML). The Lisp Clojure is itself a bit older dialect of Lisp, so maybe Scala for that? I think Lisp and Erlang are mostly about the paradigm and concepts, not about being dynamic, what do you say? Talking about the JVM, I'll raise you a Kotlin. Also noteworthy is that Groovy got static type checking with v2. As for the CLR, I must say I don't know that much have changed since F# (a dialect of ML). Basically, you've had a nice pair of cards, but they make your hand. What I'm trying to reiterate is that there seems to be a definite trend towards types.

>Turing-complete[ness]

:/

>Racket contracts [...] providing the safety guarantees in [dynamic and static] worlds.

You didn't explain what they were, so I'll assume they're runtime guards. That means they're as useful as explicit runtime checks, but don't provide safety a static type checker would provide.

> Dialyzer is a static type checker, which only rejects programs it knows for sure will result in error. Traditional type systems require the programmer to supply the proof that the code is correct and will refuse to type check without one.

So weak (algebraic data) type inference? That's better than no checking. Now as far as weak vs strong typing goes, I'll agree to disagree about type coercion here. My default is maximum safety, but I won't claim that there are absolutely no domains where explicit conversions are a "pain" without much advantage. The suspicion that there might be some was the reason for my original challenge. I really wish someone would think that through and try and convince me.

>I mentioned Forth and Assembly because these are the only languages I know of (TCL may also qualify) which are truly unityped. I suppose you'd like dynamic typing more after working with something which lacks any kind of types.

I've worked with multiple assembly languages. An assembly programmer might use your "correct programs" argument and say: "Run-time checks are a pain; I don't want to check if quacking is an option, I know something clever will happen if you just jump; don't crash my program, it's correct!". I think this a valid argument only if the check overhead is prohibitively great. But what's prohibitive about compile-time checking? Time before you can run? You can reduce that with, say, incremental compilation. Don't allow certain bug types(pun) to go unnoticed and crash your program instead. It may not be as bad as what assembly would do, but it's still catastrophic.

>the most accurate auto-complete you've ever seen: at any point, you know exactly which classes have which methods.

I have that even when the program's not running :P

>Well, in any case, you shouldn't wait to "get convinced" by someone. You should try to learn the dynamic typing side of things on your own and use it for a while. It will make you a better programmer overall, even if you get back to static typing later.

I don't know why you assume my ignorance. I've used dynamically typed languages, I've studied the concepts, it's even possible I've seen the very Smalltalk talk you were thinking about before. I choose to avoid the dynamic capabilities of my otherwise statically typed language that I use at work. I'm still open to the possibility that there's gold buried somewhere, but I am not going dig just because you imply there is. People claim a lot of things are revolutionary which aren't. Give me an example why you say something's good, convince me it's worth my time. I do the same.

My invitation to provide arguments, or a domain for dynamic languages still stands.

EDIT: (Do not read this if you are kilbertp) Shh, I'm actually watching a video on the Dialyzer now


Software safety is greatly impaired by type erasure: removing type information prior to execution.

The safest possible arrangement is one of static checks, backed by run-time checks (no type erasure).

Run-time checks are simpler and therefore much less prone to false negatives: situations when an incorrectly typed operation is permitted to proceed, with various consequences: nonsensical values, corruption, crashing and so on.

The situation of a proper type exception being thrown (dynamic language) is superior to unpredictable behavior (static-only, type-erased language where the type system failed or was subverted).

Checking types and then throwing them away is like a navy using life jackets in training and then leaving them at home when embarking on the actual campaign.


> However, it is not a matter of opinion whether software safety (and therefore availability) benefits from checks performed before run-time.

The article I linked to (it's still there for me?[1]) linked to another article[2] which in turn mentioned a paper[3], which conclusion is:

    > The data indicates functional languages are better than procedural languages;
    > it suggests that strong typing is better than weak typing; that static typing
    > is better than dynamic; and that managed memory usage is better than
    > unmanaged. [...]

    > On the other hand, even large datasets become small and insufficient when they
    > are sliced and diced many ways simultaneously, [...] Hence, we are unable to
    > quantify the specific effects of language type on usage.
So I still think there's no way to tell, for example, if a statically typed imperative language with manual memory management is better than a dynamically typed functional language with a GC. I think it's a case of "all else being equal" in the context where "all else" varies drastically.

The argument is not about if static typing improves safety (because many things do) but instead by how much and if that increase in safety is worth the drawbacks it comes with... Which again is subjective and situation-dependent.

In other words, even if we agree that static typing has a positive effect on some metric (like number of bugs) it's not going to move the discussion forward.

> Conversely, it is not a matter of opinion that dynamic languages allow patterns that static typing does not (eg. duck typing[sic]).

Not a very good example, actually there are static type systems which use structural typing to allow for type-safe duck typing. Examples are Opa with its Power Rows, OCaml with its polymorphic variants and others.

And while there certainly are techniques very hard (in terms of lines of code) to use in a statically typed language it's not like they're impossible at all (in the worst case you can write an intepreter). So the argument becomes: is a particular technique (or a set of techniques) beneficial enough to offset the lost benefits of static typing?

Given that, per the paper above, we have no hard data on how exactly static typing (much less on a dynamic typing techniques...) affects the metric we're interested in, the answer to the question is - again - a matter of personal opinion.

> These are objective arguments we can discuss, and weigh against each other. There are even studies that we can throw in here.

I'm sorry, but I'd like to trouble you to provide such papers; as you can see above my quick search returned somewhat different results.

> Basically, you've had a nice pair of cards, but they make your hand. What I'm trying to reiterate is that there seems to be a definite trend towards types.

Yeah, I also feel that argument was weak :) I only wanted to show that not "all" new languages are statically typed, I didn't want to deny that the trend exists.

The trend of "mainstream" moving to static typing is visible, but it's important to note that the same trend was observed more than once in programming history already. In all the previous cases it reversed (to dynamic typing) after ten to fifteen years. For the time being, I think, it's safer to assume we're going to repeat the cycle than that we arrived at the last iteration. This is however just an assumption and it may well be wrong!

> I really wish someone would think that through and try and convince me.

Your original thesis was that static typing is an overall win over dynamic typing. I already managed to convince you that this is not the case: you admit that there are techniques hard to pull off in a statically typed language. To me, that's enough.

My belief is that static and dynamic typing are more or less equivalent and that their impact on most metrics is rather minor. I think that the typing discipline matters little and that the safety (or any other metric) of a language cannot be determined without taking all the other features into account. Of course, this is only my belief, as there is not enough evidence to say for sure (unless there is some research I'm not aware of).

As such, I can only tell you what kind of projects I did in languages with dynamic typing. This is not the same as saying that dynamic typing is the best fit for these kinds of projects, just that there is a particular language which feature set as a whole seemed to be a good match for the problem.

As an example, I'm writing a MUD server as a pet project. MUDs are text-based games where you interact with objects using commands: go north, kill orc and the like. It's based on LPMuds' basic design, so this particular implementation is actually more of a "multiplayer REPL": the objects are described as classes (called blueprints) with arbitrary methods which you can inherit and instantiate (clone).

Every blueprint needs to be reloadable on runtime: you don't want to bring down the whole world just because you found a typo in some description. As blueprints are normal code (not just data), reloading them may change their type signatures, which needs to be handled gracefully (in both clones and inherited blueprints). Besides the predefined commands, users may evaluate arbitrary code and change the shared (persistent) environment at will. It should be possible to attach a new method to a single clone to test it without affecting anything else.

I used Io as an implementation language, because it provides most of these features out of the box: whatever was missing I added in under 1k lines of straightforward code. I was able to do so in large part thanks to a dynamic, object oriented (with multiple, prototypical inheritance) type system of Io.

It's just an anecdote, but it's an example of a project where dynamic, dynamically typed language is a clear win over a static, statically typed one.

[1] https://medium.com/javascript-scene/you-might-not-need-types...

[2] https://medium.com/javascript-scene/the-shocking-secret-abou...

[3] http://web.cs.ucdavis.edu/~filkov/papers/lang_github.pdf


>In other words, even if we agree that static typing has a positive effect on some metric (like number of bugs) it's not going to move the discussion forward.

I believe it would. Agreeing on the objective would allow us to understand the situation-dependent trade-offs, and help us to agree to disagree on subjective.

>> Conversely, it is not a matter of opinion that dynamic languages allow patterns that static typing does not (eg. duck typing[sic]).

>Not a very good example, actually there are static type systems which use structural typing to allow for type-safe duck typing. Examples are Opa with its Power Rows, OCaml with its polymorphic variants and others.

As you've said, it's still static typing, whether the types are explicit or not. Duck typing allows things to learn to quack at runtime, structural typing doesn't enable that.

>in the worst case you can write an intepreter

If you create a dynamic language, then you're using a dynamic language. Please no more Turing equivalence.

>Given that, per the paper above, we have no hard data on how exactly static typing (much less on a dynamic typing techniques...) affects the metric we're interested in, the answer to the question is - again - a matter of personal opinion.

I'm sure there is some hard data somewhere. But I like strong indications as well to decide what may be worth investigating.

>> These are objective arguments we can discuss, and weigh against each other. There are even studies that we can throw in here.

>I'm sorry, but I'd like to trouble you to provide such papers; as you can see above my quick search returned somewhat different results.

I thought I could humor you relatively easily, but my results matched yours - conclusive research on the general question seems elusive (see eg https://danluu.com/empirical-pl/). I cede the point, I'll try to pay more attention from now on.

>The trend of "mainstream" moving to static typing is visible, but it's important to note that the same trend was observed more than once in programming history already. In all the previous cases it reversed (to dynamic typing) after ten to fifteen years.

"Reversal" here seems to imply a return to a default. On the contrary, I can't say definitely that there was a time when dynamic languages ruled the mainstream.

>Your original thesis was that static typing is an overall win over dynamic typing. I already managed to convince you that this is not the case: you admit that there are techniques hard to pull off in a statically typed language. To me, that's enough.

I'm afraid my stance remained the same: I consider any advantages of dynamic languages not worthy the disadvantages. For example, the technique of duck typing counts as one of the things I said I avoided in the hybrid language I use even though it can't do structural typing. What did change is my assumption that my stance is anywhere close to being scientifically proven.

>[My MUD with dynamically reloadable objects is] just an anecdote, but it's an example of a project where dynamic, dynamically typed language is a clear win over a static, statically typed one.

Yay, a use-case! Please provide some concrete examples. Since your case is pretty niche I hope we'll be able to generalize it to say, eg. "Reloading systems is bad, availability is good", and then contrast how what happens behind the scenes to facilitate that in a dynamic language differs from what happens when you use modules or services (other than ease of use, which is a valid argument itself). Thanks.

P.S. I realized I've mangled that medium. I really hope you won't insist I read the whole thing though. It sounds too subjective from what I've read.


>> dynamic typing bubble >Could you explain this? I'm not aware of such a thing at all?

Around 2005 - 2010 there was a massive amount of proselytism on the internet in favour of dynamic languages. The likes of Steve Yegge, DHH, Zed Shaw, Mark Pilgrim, Why the Lucky Stiff, Paul Graham (with lisp) and others were constantly pushing new blog posts, articles, books about the merits of dynamic languages and new teaching material and if you were to read HN or reddit from those years you'd think it was the end of statically typed languages. You couldn't spend a day without seeing things like Ruby on Rails pop up on slashdot and other media.

Fast forward to today :

All the new languages that have gained internet fame in the past years are static. Go, Rust, Typescript, Dart. People still use lots of Java and C#. Meanwhile big companies like Dropbox are abandoning languages like Python. New projects are written in Go despite being the company that employs Guido van Rossum. Nobody talks about Google caring about python anymore either. The dynamic typing "rockstar programmers" have all but disappeared from the internet and stopped blogging/writing articles/writing books, with only one exception, Zed Shaw. The rest have either completely erased their internet presence or just become utterly silent.

There really is a moment on the internet that could be described as the dynamic bubble. Although I'd say, "dynamic echochamber" is more accurate.


Or perhaps they don't have to yell about it anymore, because so many people have been convinced.


“...William wondered why he always disliked people who said 'no offense meant.' Maybe it was because they found it easier to say 'no offense meant' than actually to refrain from giving offense.”

― Terry Pratchett, The Truth


I mean no offense to people who like dynamic typing. However, dynamic typing itself may just deserve to be dissed. But I'm not sure. So tell me if I'm wrong.

I probably shouldn't have used the word bubble, sorry. See my response to klibertp for hopefully some justification.


I sometimes wonder what it means that there's a common, concise idiom for "I'm about to knowingly say something offensive, but if you're offended it's your fault".


These days, someone will be offended by pretty much anything. So just say what you want to say. No amount of pre-apologising well help you because getting offended was their real goal anyway.


Dynamic typing isn't "unityping". It is typing, period.

For an example of a respected academic discussing dynamic typing properly, recognizing it to be typing, see Henry Baker's paper The Nimble Type Inferencer for Common Lisp.

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

In dynamically typed code, it is often possible to logically infer the type without executing it, so that the same information which is known at run-time can be ascribed to nodes of the syntax.

These are not two different type systems; it's the same information, just known at different times to some degree of completeness.

Quote from the paper:

We have chosen to perform static type inference on programs in the dynamically-typed Common Lisp programming language [CLtL84]. Common Lisp-84 has a reasonably complex type system. This system involves 42 simple type specifiers, 4 standard type operators, and 21 type specialization forms. Common Lisp has the usual primitive integer and floating point types, characters, the traditional atoms and conses of Lisp, vectors, arrays, and strings. In addition, Common Lisp has a host of non-traditional datatypes, such as hash tables, readtables, and other special purpose types. The datatype system can also be extended through user-defined structures, which are analogous to structures in C and to records in Pascal and Ada.

No nonsense here about Common Lisp having just one type, the value cell.


Sure, dynamic types are types. And nothing stops you from running a full-featured typechecker at runtime, one that can enforce useful invariants beyond “expected int but got string”.

It’s just markedly more useful to me to have that information available statically. I like being able to modify code with the assurance that the compiler will tell me about all inconsistencies. I like that the compiler can prove that its automated transformations are correct. Of course, maybe that says more about the way I work than type systems themselves.


I took that one as PARrot TCL, not "particle".


Tcl is often pronounced "tickle" by tclers.


Why not take it as both?


But why




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

Search: