6 ms·
As somebody who is afraid of types (and also, who hates types, because we all hate what we fear), may my point of view serve as balance: you don't need a type
by enriquto 2y ago
As somebody who is afraid of types (and also, who hates types, because we all hate what we fear), may my point of view serve as balance: you don't need a type system if everything is of the same type. Programming in a type-less style is an exhilarating and liberating experience:
assembler : everything is a word
C : everything is an array of bytes
fortran/APL/matlab/octave : everything is a multi-dimensional array of floats
lua : everything is a table
tcl : everything is a string
unix : everything is a file
In some of these languages there are other types, OK, but it helps to treat these objects as awkward deviations from the appropriate thing, and to feel a bit guilty when you use them (e.g., strings in fortran).
- MrMcCall 2y agoBut once you get down to the unit data values inside any of those aggregates, you're still dealing with either characters, ints, floats, strings, arrays, and they each have their own individual access patterns and, more importantly, modification functions. You can't add a number to a string, only to another number. If you are dealing with a float, you better be careful how you check it for equality. If it's pure binary, what kind of byte is it? Ascii, unicode code point, unsigned byte, signed multi-byte int, ... whatever. There's no escaping the details, friend. And your saying "everything is a word" for assembler is just plain wrong.
- enriquto 2y ago> And your saying "everything is a word" for assembler is just plain wrong. I also love x87 registers, but they are becoming rarer these days.
- MrMcCall 2y agoYour profile says "just another C hacker". I learned C from reading K&R in the late 80s. Every C compiler I've worked with could output the code as assembler, so C is really a thin layer of abstraction that wraps assembler. Having programmed in pure assembler before, I understand the benefits of C's abstractions, which began with its minimal, but helpful, type system. Should I not be taking you seriously? We are not just talking with each other but sharing our expertise with those who may be reading. Sometimes I forget that other people can just be unpleasant on purpose. I find no other explanation for your response.
- enriquto 2y agoSorry man, I was just trying to spew some harmless banter.
- MrMcCall 2y agoApology accepted. No worries. It's just that my post rate is severely limited, even to reply to people replying to me. I'm on some kind of naughty list in "the algorithm", which is something beyond dang's control, by what I gather from his reproachments to me. That's why I've got to minimize my number of replies. And 'harmless banter' doesn't communicate in pure text, friend. Peace be with you.
- erikerikson 2y ago> You can't add a number to a string Haven't written JavaScript?
- MrMcCall 2y agoI don't care if it "can" be done, the results will be garbage unless you are very, very careful. And Javascript is garbage no matter how many people use it successfully, as I have done professionally.
- SAI_Peregrinus 2y agoOr C. It just turns into pointer math. Godbolt example here[1], just make sure the `int` is an offset within the bounds of the char* and it's well-defined. [1] https://godbolt.org/z/YWKK1P7zj https://godbolt.org/z/YWKK1P7zj
- SAI_Peregrinus 2y ago> You can't add a number to a string, only to another number. Works in C, as long as the integer keeps the resulting pointer within the bounds of the allocation. See a trivial example[1]. [1] https://godbolt.org/z/YWKK1P7zj https://godbolt.org/z/YWKK1P7zj
- MrMcCall 2y agoOk, sure. But I doubt that's a good practice. In fact, I can't possibly imagine it not being a horrible idea. So, I ask: what size and signedness of int? 1, 2, 4, 8? What if the string is of length 3, 2, 1, 0? Why bother with all those corner cases. Everything has a memory layout and appropriate semantics of representation and modification. Pushing those definitions is a recipe for problems. I like to keep it simple, keeping the semantics simple in how I code specific kinds of transforms. The less kinds of techniques you use, the less kinds of patterns you have to develop, test, and ensure consistent application of across a codebase. Especially down in C land, which is effectively assembler. Gone are the days of Carmac having to save bytes in Doom, unless you're doing embedded work, in which case that's all the more reason to be very careful how you handle those bytes.
- SAI_Peregrinus 2y ago> But I doubt that's a good practice That's entirely how "string" indexing works in C. Strings in C are just pointers to `char` with some valid allocation size. As long as the integer used for the pointer offset results in a pointer into the allocation after the addition, it's valid to dereference the result. Remember, `array[index]` is syntactic sugar for `(array + index)` in C. Lots of the C stdlib string functions use this, e.g. `char strchr(const char* str, int character)` has a naive implementation as a simple loop comparing `char`s[1]. Glibc does it one `unsigned long int` at a time, as an optimization, with some extra work at the start going one `char` at a time to ensure alignment. > So, I ask: what size and signedness of int? 1, 2, 4, 8? Doesn't matter, as long as the result of the addition points to within the pointer's allocation. Otherwise you get UB as usual. > What if the string is of length 3, 2, 1, 0? Doesn't matter, as long as the result of the addition points to within the pointer's allocation. Otherwise you get UB as usual. For a 0-length string (pointer to '\0\'), the only valid value to add is 0. > The less kinds of techniques you use, the less kinds of patterns you have to develop, test, and ensure consistent application of across a codebase. 100% agreed. The less C you use for string handling the better. C strings are fundamentally fragile. [1] https://godbolt.org/z/4T835cdKb https://godbolt.org/z/4T835cdKb
- zeta0134 2y agoI feel the need to issue a correction: while I'm programming in assembly, I very well have types. This word over here (screen position) represents a positive number only, but this one over here (character acceleration) can be negative. When adding one to the other, I need to check the arithmetic flags like so to implement a speed cap... The types certainly exist. They're in my mind and, increasingly through naming conventions, embedded within some of the comments of my assembler code. But nothing is there to check me. Nothing can catch if I have made an error, and accessed a pointer to a data structure which contains a different type than I thought it did. Without a type system, that error is silent. It may even appear to work! Until 6 months later, when I rearrange my code and the types are arranged differently in memory, and only THEN does it crash.
- nottorp 2y ago> increasingly through naming conventions The original goal of hungarian notation :) But Petzold mistakenly used 'type' in the paper and we ended up with llpcmstrzVariableName instead of int mmWith vs int pixelWidth, which was what they were doing in Office and frankly makes a lot of sense.
- bluGill 2y agoI've programmed in typeless languages and they are great for small programs - less than 10,000 lines of code and 5 developers (these numbers are somewhat arbitrary, but close enough from discussion). As you get over that number you start to run into issues because fundamentally your word/array of byte/multi-dimensional array of floats/ ... has deeper meaning and when you get it wrong the code might parse and give a result but the result is wrong. Types give me a language enforced way to track what the data really means. For small programs I don't care, but types are one of the most powerful tricks needed for thousands of developers to work on a program with millions of lines of code.
- wruza 2y agoI experience it often in teams less than 2 developers and projects less than 2000 lines of code (that's still 50 pages, btw). It boils down to being able to load everything into your mind, and that heavily depends on a type of a project, data/code models, ide, etc, and also various factors unrelated to coding. A human mind is a cache -- if you overload it, something will fly out and you won't even notice. Anyone who claims that types have no use probably doesn't experience overloads. If it works for them, good, but it doesn't generalize.
- RodgerTheGreat 2y agoSure! But many, many useful programs will never need to grow to millions of LoC or thousands of developers.
- deleted 2y ago[deleted]
- igravious 2y agoruby: everything is an object
- niek_pas 2y agoHaskell: everything is a function
- usernamed7 2y agoFiles have types though: .txt, .jpg, .bin, etc.
- whilenot-dev 2y agoThe filename suffix isn't much more than part of the filename (a simple variable name in that analogy) - it's more convention than constraint. Nobody is stopping you from giving your file the name you want (and the OS allows). You'd use literal magic[0] to assume an actual type. "Everything is a file" rather refers to the fact that every resource in UNIX(-like) operating systems is accessible through a file descriptor: devices, processes, everything, even files =) [0]: https://www.man7.org/linux/man-pages/man4/magic.4.html https://www.man7.org/linux/man-pages/man4/magic.4.html
- mdaniel 2y agoAnd the good(sic) thing about conventions: so many to choose from! .htm .html .HTML .jpeg
- darioush 2y agoI'm a big fan of primitive types, in particular byte arrays. It's okay to create a new data structure that combines some primitive data types in a "struct", like an array that tracks its length. But we don't want to "build abstractions and associate behavior to them" (just associate behavior to data structures like push/pop).
- whattheheckheck 2y agoCan you expand on this please?
- darioush 2y agoSure, in many languages we have the notation of thing.do_thing(arg1, arg2). I suggest this is a good notation for data structures like, stack.push(10) or heap.pop() I'm suggesting we don't use this notation for things like rules to validate a file, so I suggest we write validate(file, rules) instead of rules.validate(file). Then we can express the rules as a data structure, and keep the IMO unrelated behavior separate. Note then we don't need to worry about whether it should be file.validate(rules) perhaps. Who does the validation belong to? the rules or the file? the abstractions that are created by non-obvious answers to "who does this behavior belong to" are generally problems for future changes.
- ks2048 2y agoIf you design a large program in C where all your variables are "char*", I suppose "exhilarating" could be one word used to describe it. The article's perspective would be that structs are useful, so use them liberally. And nearly all good, large C programs do, as far as I can tell. Of course there are tradeoffs and you can take it too far. The article mentions that as well.