27 ms·
Why static languages suffer from complexity
- dleslie 5y agoI'm unfamiliar with one of the language logos in the meme graph at the bottom: what's the red swooshy thing beside zig?
- deleted 5y ago[deleted]
- andrenth 5y agoIt's the Idris logo https://www.idris-lang.org/ https://www.idris-lang.org/
- deleted 5y ago[deleted]
- deleted 5y ago[deleted]
- guidorice 5y agoBest.Programmer.Art.Ever
- dnautics 5y agoI didn't see the article touch on the "why" explicitly, but: zig really has the chance to square this circle for low level languages, since there is duck-typed type-inferenced-coercion in places where it makes sense. Completely correct about zig not necessarily being good for higher level stuff, but I think (dynamic) HLLs have been converging on dealing with this using static typechecking, with varying levels of success
- peterashford 5y agoI spent a couple of days with Zig. Thought the language was great but the tooling (on Windows) just killed it for me. I hope that gets better 'cos I'd like to give it another go
- preseinger 5y ago> I cannot imagine a single language without the if operator, but only a few PLs accommodate full-fledged trait bounds, not to mention pattern matching. This is inconsistency . . . How? > Sometimes, software engineers find their languages too primitive to express their ideas even in dynamic code. But they do not give up . . . Is this a failure of the language, or a failure of the engineer? > If we make our languages fully dynamic, we will win biformity and inconsistency,[^] but will imminently lose the pleasure of compile-time validation and will end up debugging our programs at mid-nights . . . One possible solution I have seen is dependent types. With dependent types, we can parameterise types not only with other types but with values, too. Types are a productive abstraction/model in programming languages. One of many. Each has its strengths and weaknesses; each is appropriate in some circumstances and not in others. Types are not the solution to all problems, any more than currying or OOP or whatever else is.
- gumby 5y ago> > I cannot imagine a single language without the if operator… Production languages (like prolog or make) don’t need an if statement or operator as selection is implicit when a production matches.
- preseinger 5y agoI'm not sure I buy your premise -- `make` is a DSL for a very narrow set of problems, and I've never encountered Prolog in production use?
- jayd16 5y agoShader languages are also hellbent on avoiding branches too so if is frowned upon and often not used. I could easily imagine not having it in a shader language.
- raphlinus 5y agoThis is very much changing. IMHO, doing shader language design today, you should give let the programmer express things in the most natural way possible, and let the compiler figure out whether to generate a branch or branchless code. Yes, often you want the latter, but compilers are pretty good at figuring that out.
- ModernMech 5y agoUgh, I know I'm getting old when I don't understand the memes.
- seanw444 5y agoI really want to know where I can find quality programming memes like these. Not just the generic "haha language ___ is bad, nerd" memes.
- dandotway 5y agoSo whenever I have to study someone else's 'dynamic' python I encounter this sort of thing: def foo(bar, baz): bar(baz) ... What the heck is 'bar' and 'baz'? I deduce no more than 'bar' can be called with a single 'baz'. I can't use my editor/IDE to "go to definition" of bar/baz to figure out what is going on because everything is dynamically determined at runtime, and even grep -ri '\(foo\|bar\|baz\)' --include \*.py Won't tell me much about foo/bar/baz, it will only start a hound dog on a long and windy scent trail.
- nicoburns 5y agoThe real power of dynamic languages is being able to do: const foo = JSON.parse(arbitraryJsonString); and not having to worry about the structure up front.
- naasking 5y ago> The real power of dynamic languages is being able to do: const foo = JSON.parse(arbitraryJsonString); and not having to worry about the structure up front. That's not power, that's a shotgun aimed at your crotch whose trigger is connected to a cosmic ray detector.
- dandotway 5y ago+NaN For comments that make me laugh out loud for duration T>2.0 seconds, I wish HN provided a way to transmute/sacrifice one's past karma points into additional +1 mod points.
- laumars 5y agoThat’s not a capability unique to dynamic languages
- valcron1000 5y agoWhat's 'foo' and what you can do with it?
- 5y ago
- batrachos 5y agoI dislike the phrase 'dynamic language' and especially dislike the phrase 'static language'. We should say 'dynamically typed' or 'statically typed', because 'static' languages are the site of major dynamism.
- chriswarbo 5y agoI think 'dynamic language' is appropriate here, since it's not only talking about types; it's largely talking about macros, pre-processors, reflection, etc. too. Also, the main argument is that separating features into those used at compile-time (AKA static) and run-time (AKA dynamic) is necessarily creating separate languages (i.e. a "static language", which may involve types, macros, preprocessors, etc.; and a "dynamic language", which may involve memory allocation, branching, I/O, etc.)
- honkycat 5y agoGreat article, made me think! However, I think it needs to be trimmed down. Making your argument in the final paragraph of the article is not great. Hoist the "Final Words" section to the top and make it a "tldr" introduction, that way your reader can begin with a high level understanding of your argument, which you can hone and refine as you progress.
- devit 5y agoYeah, the current problem is that Idris code is far less efficient than Rust code, because Idris boxes everything and erases all types, and also Idris's support for borrowing seems less powerful than Rust (it lacks first-class mutable borrows as far as I can tell). It seems that fixing this is a research problem, which would lead to the holy grail of programming languages, i.e. an ultimate language that is as expressive as Idris and as efficient as Rust, and is thus essentially perfect.
- siknad 5y ago> an ultimate language that is as expressive as Idris and as efficient as Rust, and is thus essentially perfect. Are both Idris's expressiveness and Rust's efficiency (given stronger guarantees) perfect? Aren't theese languages really complex both to learn and to write? There are poblems without a solution, perfect and unique to all of them.
- dwohnitmok 5y ago> Idris's support for borrowing seems less powerful than Rust (it lacks first-class mutable borrows as far as I can tell). Depends on what you mean. Idris's notion of multiplicities essentially subsumes Rust's borrowing (there's some differences with affine vs linear types), so I can't think off the top of my head of things that you can ensure with Rust that you can't with Idris, but Rust has a lot more quality of life improvements that make things less clunky (also having a GC, Idris can get away with a lot less need for borrowing in the first place).
- preseinger 5y agoExpressiveness is not an unambiguous net good -- more expressiveness is not a priori better. Expressiveness carries costs of comprehension and coherence that need to be appropriately weighed in the contexts where the language will be applied. Programming languages are not theoretical things. They're concrete, practical tools that _enable_ other stuff. Engineering, not science.
- ImprobableTruth 5y agoHow would you define expressiveness (as its commonly used, so a definition where Turing complete languages can have different expressiveness) if not as how much something can be simplified and thus aiding comprehension, rather than detracting from it? >Programming languages are not theoretical things. They're concrete, practical tools that _enable_ other stuff. Engineering, not science. You can't escape theory, engineering is applied science.
- adamddev1 5y agoI wonder where TypeScript would fall on this language continuum?
- dnautics 5y agoMy guess: It wouldn't because this is about static languages. Typescript is still a dynamic language with a very smart (probably best-in-class at this point in time) compile-time typechecker/static analysis tool.
- AtNightWeCode 5y agoThis is some kind of joke, right?
- armchairhacker 5y ago"Why not add X feature? If people don't want to use X, they just don't, and there are basically 0 downsides." In theory this is true. If the compiler is decent, compile times and analysis shouldn't really be affected. Maybe libraries will use X but otherwise they would use a manual implementation of X anyways. But in practice developers misuse features, so adding a feature actually leads to worse code. It also creates a higher learning curve, since you have to decide whether to use a new feature or just re-implement it via old features. See: C++ and over-engineered Haskell. So each feature has a "learnability cost", and only add features which are useful enough to outweigh the cost. But most features actually are useful, at least for particular types of programs. It's much harder to write an asynchronous program without some form of async; it's much harder to write a program like a video game without objects. This may be controversial, but I really don't like Go and Elm (very simple languages) because I feel like have to write so much boilerplate vs. other languages where I could just use an advanced feature. And this boilerplate isn't just hard to create, it's hard to maintain because small changes require rewriting a lot of code. So ultimately language designers need to balance number of features with expressiveness: the goal is to use as few simple but powerful features to make your language simple but really expressive. And different languages for different people. Personally I like working with Java and Kotlin and Swift (the middle languages in the author's meme) because I can establish coding conventions and stick to them, C++ and Haskell are too complicated and it's harder to figure out and stick to the "ideal" conventions.
- preseinger 5y agoAbsolutely agree. All features are useful. That's table stakes. But usefulness is insufficient to warrant inclusion. How does a feature interact with all existing features? Are there ambiguities? Are there conflicts? A language is not a grab-bag of capabilities, it's a single cohesive thing that requires design and thought.
- throw10920 5y ago> But in practice developers misuse features, so adding a feature actually leads to worse code. Is that really a problem on the language's side, though? Devs are capable of mis-using any feature, even extremely basic ones that almost every language has (variable names, for instance (although I'm laughing in FORTH)). Code standards and code reviews are necessary tools in the first place because it doesn't matter what language you give a programmer - they're perfectly capable of constructing a monstrosity in it. I argue that preventing programmers from doing dumb things with well-designed language features (so, hygenic Scheme macros, and not raw C pointers) is a social and/or organizational problem, and it's better to solve that at that level than to try to solve it (inadequately) at a technical level. ("I keep dereferencing null pointers", on the other hand, is an example of a technical problem that can be solved on the technical level with better language design)
- erichocean 5y agoFWIW, I've been developing code directly in MLIR recently, and in MLIR "Comparing types is cool" is indeed true. It's amazing what you can do when you have compiler transformations and targets always available. Suddenly, "little DSLs" (MLIR dialects) don't seem so bad, since they are defined the same way and map in semantically-sound ways to lower-level dialects. You can have dedicated dialects, like Halide, for doing something as concrete as image processing kernels. Oh, and you can output those kernels to both the CPU and GPU, including automatically introducing async functions, host-side sync barriers, etc. Good luck doing that automatically with a general purpose programming language and a combination of macros, AST manipulations, and derived types! You really need a compiler to stay sane. > "Programming languages ought to be rethought." Indeed.
- raphlinus 5y agoCan I pick your brain on MLIR? It sounds awesome from what you describe, but I want to know more about whether it's specialized to machine learning types of workloads or whether it's good for more general things.
- erichocean 5y agoWell, we're using it for business automation. We have automated agents that are selectively override-able by humans on an as-needed basis (e.g. a case we don't currently handle, or because of a runtime error). Also, most of our code needs to support suspend/resume on another machine, either in the middle of an action or more often between actions. So, a "behavior" might begin on machine A and then migrate to machine B to do more work, then on to machine C. While doing work, its execution state might be serialized to Postgres while some dependency is waited on—say, a human task that doesn't get done until the following Monday. It's then resumed in the same execution state, potentially on an entirely different worker/machine, and continues executing. The suspend/resume stuff completely destroys the code if you're writing it by hand, as does moving from machine to machine. So we write the core logic in our own internal MLIR dialect and then output code that has the suspend/resume semantics automatically (i.e. literal compiler transformations, plus our own "interpreter" (which is just JavaScript/v8 with all of the extra suspend/resume cruft added in). We don't translate out of SSA form at all, our codegen can execute it directly. We also insert debug hooks so when there's an error, you can map the execution state to the original code. Most of the cool machine learning stuff MLIR can do, we're not even doing yet outside of some internal prototypes. So far, just the methodology of MLIR has made a huge impact—it gives really nice structure (read: tooling) for the kinds of code transforms we've needed to do. HTH
- arc619 5y agoThis entire article can be summarised as "compile time stuff should use the same language as run time". I guess the author just hasn't encountered Nim before, where anything becomes compile time by just assigning to a const, and macros have access to the real AST without substitution. Macros also allow compile time type inspection, as they are a first class citizen rather than tacked on. The compile time print, AFAICT, already exists in Nim as the `&` macro in strformat. That lets you interpolate what you like at compile time, and supports run time values too.
- foxfluff 5y ago> This entire article can be summarised as "compile time stuff should use the same language as run time". I think the message is more nuanced than that (otherwise wouldn't lisp with its homoiconicity and compile time macros fit the bill perfectly?). Idris uses the same language, but is still too complex. And Zig not general purpose enough. I don't want to put words in the author's mouth but I think the implication is that this is a large space to explore and we don't have a solution yet; there's nothing like "just make your language like this and it'll be good." They're just pointing out the problem they see, and some (non-)solutions to it.
- Hirrolot 5y ago+1
- arc776 5y ago> I think the message is more nuanced I thought it was more nuanced too as they were explaining how integer types can be derived, until I finished the article, and they really did just seem to be complaining that there's a mismatch between compile time and run time. Dynamic types don't really solve the problems they mention as far as I can tell either (perhaps I am misunderstanding), they just don't provide any guarantees at all and so "work" in the loosest sense. > otherwise wouldn't lisp with its homoiconicity and compile time macros fit the bill perfectly? That's a good point, I do wonder why they didn't mention Lisp at all. > we don't have a solution yet What they want to do with print can, as far as I can see, be implemented in Nim easily in a standard, imperative form, without any declarative shenanigans. Indeed, it is implemented as part of the stdlib here: https://github.com/nim-lang/Nim/blob/ce44cf03cc4a78741c423b2b3963b48b6d9e6755/lib/pure/strformat.nim https://github.com/nim-lang/Nim/blob/ce44cf03cc4a78741c423b2... Of course, that implementation is more complex than the one in the article because it handles a lot more (e.g., formatting and so on). At the end of the day, it's really a capability mismatch at the language level and the author even states this: > Programming languages ought to be rethought. I'd argue that Nim has been 'rethought' specifically to address the issues they mention. The language was built with extension in mind, and whilst the author states that macros are a bad thing, I get the impression this is because most languages implement them as tacked on substitution mechanisms (C/C++/Rust/D), and/or are declarative rather than "simple" imperative processes. IMHO, most people want to write general code for compile time work (like Zig), not learn a new sub-language. The author states this as well. Nim has a VM for running the language at compile time so you can do whatever you want, including the recursive type decomposition (this lib isn't implementing Peano arithmetic but multiprecision stack based bignums): https://github.com/status-im/nim-stint https://github.com/status-im/nim-stint and specifically here: https://github.com/status-im/nim-stint/blob/ddfa6c608a6c2a843d7b405f377a22703947267a/stint/intops.nim#L19-L25 https://github.com/status-im/nim-stint/blob/ddfa6c608a6c2a84... func zero*[bits: static[int]](T: typedesc[Stuint[bits] or Stint[bits]]): T {.inline.} = ## Returns the zero of the input type discard func one*[bits: static[int]](T: typedesc[Stuint[bits]]): T {.inline.} = ## Returns the one of the input type result.data = one(type result.data) It also has 'real' macros that aren't substitutions but work on the core AST directly, can inspect types at compile time, and is a system language but also high level. It seems to solve their problems, but of course, they simply might not have used or even heard of it.
- chriswarbo 5y agoI think the comparison between printf in Idris and Zig is a little off, since the Idris version defines an intermediate datastructure, and hence requires extra parsing and interpreting functions for it. That's a nice approach, but the Zig version is operating directly on characters, so it's a bit apples-to-oranges. We can get a more direct Idris implementation by inlining the parser (toFmt) into the interpreter (PrintfType). That lets us throw away `Fmt`, `toFmt`, etc. to just get: PrintfType : (fmt : List Char) -> Type PrintfType ('*' :: xs) = ({ty : Type} -> Show ty => (obj : ty) -> PrintfType xs) PrintfType ( x :: xs) = PrintfType xs PrintfType [] = String printf : (fmt : String) -> PrintfType (unpack fmt) printf fmt = printfAux (unpack fmt) [] where printfAux : (fmt : List Char) -> List Char -> PrintfType fmt printfAux ('*' :: fmt) acc = \obj => printfAux fmt (acc ++ unpack (show obj)) printfAux ( c :: fmt) acc = printfAux fmt (acc ++ [c]) printfAux [] acc = pack acc
- dvh 5y agoWould printf even exist if C had sane strings?
- foxfluff 5y agoHow is formatted printing related in any way to the internal representation of strings? printf is what you call when you want to print X in hexadecimal with at least two digits, left justified on an eight-character wide field. I don't see how the sanity of whatever string representation the programming language uses is relevant here.
- msla 5y agoSome kind of formatting function would because sometimes, you really do need to print an integer with enough leading zeroes to fit in a five-digit field.
- peterashford 5y agoprintf exists in Java. Because its so bloody useful.
- goldsteinq 5y ago
- tempodox 5y agoThis article spends many words to say, “there is no silver bullet”. But dynamically typed languages produce at least the same amount of accidental complexity, just in different ways.
- Hirrolot 5y ago> This article spends many words to say, “there is no silver bullet”. Rather "I believe there is a silver bullet, but I don't know where yet". Probably I am too naive!
- lambdasquirrel 5y agoIndeed, the article has it backwards. The types are always there. Your program will fail at runtime if it's not correct. The type system merely surfaced that. Complexity in the types happens when the type system isn't expressive enough. Or when you're trying to do something that would make the compiler try to solve the halting problem. To that last point, this is why the PLT community has pushed in the direction that Agda / Idris has. Kind of like how we realized years (decades?) ago that we didn't need pointer arithmetic, there's been a realization that "total" isn't actually that helpful, and it's okay if we didn't have languages that could express the halting problem.
- skybrian 5y agoThat's the hope, but saying there's something wrong is insufficient. The compile-time errors need to be understandable, or it's just going to be frustrating. Maybe we should judge compile-time constraint systems by how easy it is for the library author to add good error messages for misuse?
- adamrezich 5y ago> Kind of like how we realized years (decades?) ago that we didn't need pointer arithmetic who's "we" here? pointer arithmetic is useful for all kinds of things.
- Animats 5y agoFascination with type systems does not seem to be all that useful in practice. Go has a minimal type system, and is able to do much of Google's internal server side work. Most of the problems that cause non-trivial bugs come from invariant violations. At point A, there's some assumption, and way over there at point B, that assumption is violated. That's an invariant violation. Type systems prevent some invariant violations. Because that works, there are ongoing attempts to extend type systems to prevent still more invariant violations. That creates another layer of confusing abstraction. Some invariants are not well represented as types, and trying makes for a bad fit. What you're really trying to do is to substitute manual specification of attributes for global analysis. The Rust borrow checker is an invariant enforcer. It explicitly does automatic global analysis, and reports explicitly that what's going on at point B is inconsistent with what point A needs. This is real progress in programming language design, and is Rust's main contribution. That's the direction to go. Other things might be dealt with by global analysis, Deadlock detection is a good example. If P is locked before Q on one path, P must be locked before Q on all paths. There must be no path that leads to P being locked twice. That sort of thing. Rust has a related problem with borrows of reference counted items, which are checked at run time and work a lot like locks. Those potentially have a double-borrow problem related to program flow. I've heard that someone is working on that for Rust.
- DonaldPShimoda 5y ago> Fascination with type systems does not seem to be all that useful in practice. > ... > The Rust borrow checker is an invariant enforcer. [...] This is real progress in programming language design, and is Rust's main contribution. I'm so confused by your stance here. You essentially say "type systems are not useful" and then "oh but this most recent advance in type systems — that one is useful." Do you find type systems useful or not? There are a lot of properties we can analyze statically, and practically all of them essentially amount to extensions of type systems. Any of them increases our ability to rule out undesirable programs from every beginning execution. Some of them have unintuitive syntax, but many of them are no more syntactically burdensome than most other type systems. This is especially true if you consider how far we've come with type inference, so we no longer have to write code with the verbosity of Java just to get some meager guarantees. It's still a very active area of research, but we're clearly making progress in useful ways (which you even highlight), so I don't really know what point it is you've set out to make.
- Zababa 5y agoIn the SML/OCaml world there's something like that: there is a difference between types and modules, and functions (from types to types) and functors (from module to module). Work was done on 1ML to unify everything: https://people.mpi-sws.org/~rossberg/1ml/ https://people.mpi-sws.org/~rossberg/1ml/. An extract: > In this "1ML", functions, functors, and even type constructors are one and the same construct; likewise, no distinction is made between structures, records, or tuples. Or viewed the other way round, everything is just ("a mode of use of") modules. Yet, 1ML does not require dependent types, and its type structure is expressible in terms of plain System Fω, in a minor variation of our F-ing modules approach. > An alternative view is that 1ML is a user-friendly surface syntax for System Fω that allows combining term and type abstraction in a more compositional manner than the bare calculus. On the other hand, from the "engineer" point of view, all abstractions melting into one may not be desirable. It's nice to be able to use weak abstractions for simple stuff and powerful abstractions for more powerful stuff. Being exposed to the full complexity of your language all the time sounds like a recipe for disaster.
- preordained 5y agoHaving used Clojure for a while now, I will say having 90% of things be a primitive, map, or vector goes a long way in and of itself. A lot of types concocted in a more conventional language just don't need to exist, IMO, and they create so much baggage around themselves.
- Zababa 5y agoYou know what they say about people with hammers.
- zmmmmm 5y agoHmm, how well does this scale though? you are passing around these giant maps of vectors of tuples and then you pass it to someone unfamiliar with the code, how the hell do they know what's in there? Is the order price the first element of the tuple or the second? What happens when I refactor things and now all the tuple elements shift over one? Surely you'll end up writing just as much in documentation as you would have to specify the types? Currently working my way through some complex Python code written in that style and it's completely impossible to understand it. In fact, the only way I can actually do it is transforming all these ad hoc data structures into proper types so I can make sense of it.
- spinningarrow 5y agoIf your data is not position-dependent a tuple doesn’t sound like the correct choice. In the price example you provided, a map would be much better. As for how you know what’s in there - you should only know whether what’s relevant to your function is in there and not care about the rest of the world. For the former, tools like clojure.spec are helpful but ultimately good design helps the most (something that typed languages can often obscure).
- yakshaving_jgt 5y ago> If your data is not position-dependent a tuple doesn’t sound like the correct choice. That's kind of the problem though. Software is written by humans, and humans are fallible. We don't always make the correct choices. Also, there are economic pressures, deficiencies in specification, and changes in business requirements. Personally, I believe businesses should accept the aforementioned reality and optimise for cost of change.
- lowbloodsugar 5y ago"We might want to zip our car with their car..." We do or we don't. There is no "might". Spending money on "might" has been the death of many projects. If we didn't, and now we do, we could write a fn to map the car to parts, or we could define the car struct in terms of its parts, or we could just do away with the car altogether. But far more valuable would be an analysis of what changed about the requirements that the model no longer works. Now, don't get me wrong: I'd love a better language, and by better I mean "as fast as assembly but 'dynamic'". The problem is that, at the end of the day, all compilers are just "premature optimizations" or perhaps "willing premature optimizations". We could all be happily programming in smalltalk or build a runtime using predicate logic, but a) the number of people who could program in it is vanishingly small and b) it would be fucking slow. These languages don't solve a problem that I have, or rather they don't solve a problem that I don't already have a far better solution for. They solve a problem that academics have.
- deleted 5y ago[deleted]
- zmmmmm 5y agoThe problem I find with static typing is that it so easily leads you over-specifying the requirements / constraints. In fact, it makes such a virtue out of that over-specification that many people would consider it a best practice to do so. For example, perhaps my `calculate_price` function only depends on 2 attributes of the order which has 65 attributes. Am I creating a 2-element data type for that function to process? no! I'm specifying that it processes an Order data type, with all its 65 elements. But implicitly then I'm saying the function has 65 input parameters of all these specific types and nobody can call it now without providing them all. What a pain! Huge amount of extra code, refactoring, unit testing, because of this. So either you end up with a cambrian explosion of micro-types or you have these way overspecified interfaces everywhere. Compare with dynamic languages (or structural typing, Go etc) that only care that things "quack like a duck". The calculate_price function doesn't care what object you give it, as long as it has the two attributes it needs. Now I can unit test `calculate_price` with a 2-element object rather than needlessly creating the 23 irrelevant required elements of a valid Order. I think a lot could be solved with culture shift. Where data types are really known and locked in, use the crap out of them. As soon as things get ambiguous or flexible, go right ahead and specify that your function takes a Map<String,Object>. If a useful concrete interface emerges at some point factor it out then. The problem is that this is really frowned upon in a lot of places.
- mdoms 5y agoOr you could just take the two parameters you're actually using on your function. No new type, no need to pass your mega-object, just take two nice strongly typed arguments.
- brundolf 5y agoYou’re putting structural types in the same boat as dynamic types, which I don’t think is fair. Some of the most popular static type systems out there have structural typing, including Go (as you mentioned) and TypeScript. And that’s not even getting into languages that do extensive type-inference, including TypeScript Haskell and ReScript (which also saves you from locking into over-broad contracts).
- 5y ago
- AndyKelley 5y agoThis article incorrectly states that Zig has "colored" `async` functions. In reality, [Zig async functions do not suffer from function coloring](https://kristoff.it/blog/zig-colorblind-async-await/ https://kristoff.it/blog/zig-colorblind-async-await/). > Yes, you can write virtually any software in Zig, but should you? My experience in maintaining high-level code in Rust and C99 says NO. Maybe gain some experience with Zig in order to draw this conclusion about Zig?
- chrisaycock 5y agoDebating language design with people who don't actually know the language (or understand the features) is extremely frustrating. But anyway, thanks for your work on Zig. Your metaprogramming concepts were heavily influential for some of the ideas in my own language, Empirical.
- MrBuddyCasino 5y ago> incorrectly states that Zig has "colored" async functions This was indeed weird to read, given that only Zig (and soon the JVM) solves this problem, and is well known for the fact. Especially when language design and type theory are an area of interest. But hey, silver lining: Zig still kind of came out on top.
- pyrale 5y agoI must admit I was very surprised so see what started as a static-types rant ending up extolling the merits of Idris.
- mbrodersen 5y agoAlmost all software running the world is written in statically typed languages. This is not by accident or because developers don’t know better. Every few months on HN somebody will make some new claim about why dynamically typed languages are somehow better. But the truth is that statically typed languages have won in the market place for real world software. And I don’t see anything changing that.
- bcrosby95 5y agoThe article is about attempting to escape this static vs dynamic dichotomy, not about declaring dynamic languages superior to static ones.
- mbrodersen 5y agoYes you are right. And I do agree with the author regarding Dependently Typed languages.
- darthrupert 5y agoToday I learned that python, javascript and php are statically typed languages.
- Too 5y agoAny hygienic team using those today, are using analyzers on top, like mypy, hhvm or typescript.
- mbrodersen 5y agoPython, JavaScript and PHP run on runtimes written in statically typed languages. And those runtimes run on operating systems written in statically typed languages, using hardware drivers written in statically typed languages. So yes the world does indeed run on statically typed languages. The code you write in Python/JavaScript/PHP is a thin layer on top of C/C++.
- chubot 5y agoNice article! Highly related discussions: https://github.com/fsharp/fslang-suggestions/issues/243#issuecomment-916079347 https://github.com/fsharp/fslang-suggestions/issues/243#issu... https://old.reddit.com/r/ProgrammingLanguages/comments/placo6/don_syme_explains_the_downsides_of_type_classes/ https://old.reddit.com/r/ProgrammingLanguages/comments/placo... F# designer Don Syme is making the "biformity" argument, e.g. needing a debugger for compile time as well as runtime. and Syme & Matsakis: F# in the Static v. Dynamic divide https://old.reddit.com/r/ProgrammingLanguages/comments/rpcm65/syme_matsakis_f_in_the_static_v_dynamic_divide/ https://old.reddit.com/r/ProgrammingLanguages/comments/rpcm6... I still think something an application language with something like Zig's comptime would fill a big niche. (As opposed to a systems language.)
- lincpa 5y ago
- aabbcc1241 5y agoOne way to do dynamic macro in static type language is to generate the source code using the host language as separate build process before the compilation of hand-written and generated source code. For example in Typescript, I use tsc-macro to run "*.macro.ts", they can import any functions and modules just like normal source code. And their evaluated result are saved as "*.ts" The generated ts are then compiled alone with other hand-written typical source files into js for deployment and execution.