Earlier quoted context omitted.
I agree; in my experience, pretty much everything is ETL. We take data from one thing, change it a bit, and put it somewhere else. Sometimes, as a treat, we take data from two things, put them together, and then put that somewhere else. Frontend, backend, databases, services, reports, whatever - ETL. In that context, the types and transformations between types are the most important feature. (Everything is actually C…
I remember working on an ETL pipeline in Airflow years ago and thinking: "we're defining and programming an abstract computer". I guess with general computers everything we do is basically defining nested specific computers. That's, I think, the insight behind SmallTalk and the original concept of objects it used: the objects were supposed to represent computers and the message passing was an abstract network layer.
Don't Be Afraid of Types
201–210 of 233 posts
Re: Don't Be Afraid of Types
#202As 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…
I'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).
Re: Don't Be Afraid of Types
#203Earlier quoted context omitted.
> 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
Ok, 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,…
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.
Re: Don't Be Afraid of Types
#204Earlier quoted context omitted.
It's more cognitive load to write a validation for every parameter because you can't rely on your fellow dev knowing it's not good to pass a string where you want a boolean.
I think you misunderstood the article and my comment: this is about introducing new types, not about typing or not typing your function arguments.
Re: Don't Be Afraid of Types
#205Earlier quoted context omitted.
OO (as a data container or not) fits into some domains very well. Gonna get stuff from a database? Objects are great. Want to move something without being accidentally written/corrupted? Objects are great. Want to model a 3D object with per node/face/$ANYTHING properties, objects are great. Does object handle everything? Of course not, but having it as a capability at hand allows some neat tricks and tidy code. I bel…
Objects are famously bad at (relational) databases, hence a near universal loathing of ORMs.
Re: Don't Be Afraid of Types
#206People might be afraid of types because in OOP land there's the idea that types aren't mere containers for data. You have to use encapsulation, inheritance and polymorphism. Fields and properties shouldn't have public setters. You assign a value only through a method, otherwise you make the gods angry. You have gazillions of constructors, static, public, protected, private and internal. And you have gazillions of met…
Re: Don't Be Afraid of Types
#207Earlier quoted context omitted.
Uncle Bob in particular is a funny case. I feel like his books are largely credited as the being source those very particular OOP obsessions But he eventually turned to the dark side. He claims clojure, a functional lisp, is his absolute favorite language. He’s even got blog posts about it! Multiple! I stumbled on this while reading about clojure. I really like his blog! https://blog.cleancoder.com/uncle-bob/2019/08/…
Holub [1] helped clarify this for me. Functional programming can express patterns just as well as OOP. Implementations--idioms--of a pattern can appear different but still retain its design purpose. Previously, I thought FP was a way to happy-path incidental habits to avoid studying every pattern. But if patterns are discovered, arise out of independently invented idioms, then the best I could do is reinvent what eve…
No! Patterns are just crutches for missing language features or "design patterns are bug reports against your programming language." GoF patterns are concepts useful in OOP, but the recurring patterns and architectures you see in other paradigms are totally different. And they don't apply to Lisp: https://www.norvig.com/design-patterns/ Most don't even apply in Go: https://alexalejandre.com/programming/software-architecture-...
> visitor is type switching, singleton global variables, command and strategy are first class functions with closures, state is building a state machine with first class functions
If you could perfectly compress your code, repeated patterns would be factored away. Macros do this. In Lisp, when you find a pattern, you write code which generates that pattern, so you don't have to.
https://mishadoff.com/blog/clojure-design-patterns/
> if patterns are discovered, arise out of independently invented idioms
Yes. That's the point behind Christopher Alexander's pattern concept - he found architectural patterns which seemed to promote good social habits, happiness etc. Gabriel's Patterns of Software presents this far better than GoF. I strongly suggest you read it: https://www.dreamsongs.com/Files/PatternsOfSoftware.pdf
Re: Don't Be Afraid of Types
#208Earlier quoted context omitted.
Ok, 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,…
> 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 function…
Any time the microprocessor accesses memory for use as an int, it's a specific kind of int, meaning size and signedness, and the flags are adjusted properly as per the operation performed.
> Strings in C are just pointers to `char` with
I'm gonna end this here. I taught myself C programming by reading K&R in the late 80s, and then proceeded to do so professionally for YEARS and YEARS.
There are people that know, and there are people that act like they know. You ever read the first two chapters of Windows Internals? You ever write C code that could make Windows system calls from the same program that could be 32- or 64-bit with a simple compiler flag?
I have.
> C strings are fundamentally fragile.
Not if you know what you're doing. You're almost certainly using a C program to type this response in an operating system largely written in C. You get any segfaults lately? I don't EVER on either my Ubuntu or Debian systems.
Thanks for playing.
Re: Don't Be Afraid of Types
#209Earlier quoted context omitted.
Mostly agree, but there are methods that truly are best co-located with their (immutable) data. A good example is Point.Offset(deltaX, deltaY) which returns a new point relative to the callee. Why force that into a static class? There are plenty of examples where you want to use an abstraction over various immutable record types. Services vs. records is a false dichotomy and there is power in mixing the two. Yes, the…
> Yes, there are lots of functions that don't make sense to co-locate with their operands. May I ask for one or two examples?
For a more complex example, let's consider mixing colors.
Say we have red = ColorRGB(196, 0, 0) and blue = ColorRGB(0, 0, 196) and our current task is "allow colors to be mixed". Which looks better:
purple = red.MixWith(blue) or
purple = Color.Mix(red, blue) ?
There are many different ways to mix colors, and many other things you might want to do with them too. When you start getting into things like red.MixHardLight(blue) vs.
ColorMixing.HardLight(red, blue)
The advantage of the latter becomes more clear. And it naturally extends into moving your mixing into an interface instead of a static class, so you can have "ColorMixer.Mix(red, blue)", etc. It's about focusing more on the operation you're doing than the nouns you're doing them on, which just tends to be a cleaner way to think about things. There's just a lot more variety in "different operations you can do with things" than in "types of things", at least in the kind of software development I've experienced.Re: Don't Be Afraid of Types
#210Earlier quoted context omitted.
I don't think this is what lasagna means. Lasagna is when you have your software organized in layers. In other words instead of having a big ball of mud where A calls B calls C calls A calls C calls B you have layers (like in lasagna) so that A calls B calls C and you keep your code base so that classes/modules/types that are in the lower layer do not depend on or know of the anything above them and the dependencies…
Not trying to be funny, but "Ravioli code" might be closer: https://stackoverflow.com/questions/2052017/ravioli-code-why... https://en.wikipedia.org/wiki/Spaghetti_code#Ravioli_code A related principle that I don't think is talked about enough is "locality": I'd rather have all the code about one feature in one file or close together, rather than it strewn across files where it's harder to read and understand as a wh…
I have this issue with: Java, Kotlin, Erlang, and Elixir, but especially Java and Kotlin.