3 ms·
I find statically typed code harder to read and maintain on average because interfaces tend to be more complex on average. With dynamically typed languages, the
by socketcluster 1y ago
I find statically typed code harder to read and maintain on average because interfaces tend to be more complex on average. With dynamically typed languages, there is more pressure to keep the function signatures as simple as possible as developers try to work around their mental limitations of remembering all the types.
IMO, the value of simple interfaces is enormous and yields substantial benefits in terms of separation of concerns and modularization. The benefits of such architecture make arguments around static vs dynamic types pointless.
Once you know how to architect code properly and test appropriately, it makes almost no difference whether the languages is statically typed or dynamically typed... A lot of the constraints of static typing become annoyances.
The most infuriating line I hear from proponents of dynamically typed languages is how statically typed languages make refactoring easier. It's infuriating because I know exactly what they mean but it's incorrect. Having coded with statically typed languages, I'm familiar with the feeling of refactoring code and "the friendly compiler" guiding me and reminding me of all the places were I forgot to update the code when I changed one of the types... But unfortunately, the very fact that refactorings often require updating code in so many places is a testament to poor architecture. I don't have this problem when refactoring dynamically typed codebases. On average, the code is more modular. With dynamically typed languages, people don't try to design types that cut across the entire codebase. Oftentimes, many 'refactorings' in static typed land are just type modifications which wouldn't even be a problem in the first place if a dynamically typed language was used.
- AlotOfReading 1y agoThis doesn't match my experience. For an apples-to-apples example, here's the first function I found in numpy, compared to widely used libraries in C++ and JS: MathJs: https://mathjs.org/docs/reference/functions/reshape.html https://mathjs.org/docs/reference/functions/reshape.html NumPy: https://numpy.org/doc/stable/reference/generated/numpy.reshape.html#numpy.reshape https://numpy.org/doc/stable/reference/generated/numpy.resha... Eigen (C++): https://libeigen.gitlab.io/eigen/docs-nightly/classEigen_1_1DenseBase.html#a26c8e50a4d3e3d51a979aa59460a7347 https://libeigen.gitlab.io/eigen/docs-nightly/classEigen_1_1... The JS one is simple enough, but even here be dragons. The "number" type supports storing decimals like 2.3. There's an isInteger() function on it that's never used, and the implementation doesn't actually check that they're integers as far as I can tell. It's anyone's guess what happens when you violate the docs-only requirement for integral values only. Moreover, -1 is a sentinel value indicating autosize, so there are non-integral values that are accepted. The numpy interface is worse. First off, fully static typing would involve dependent types here. We'll ignore that. Then you have the shape parameter, which is a structure of "ints". What do ints mean here? Any number of things, from python native bigints to np machine types. It also takes sentinel values. The order parameter is the real nightmare here though. Using this effectively is incredibly difficult because numpy doesn't want to constrain itself by specifying memory layout. But choosing appropriately here requires knowing that! Of course we could also just look at the static typing annotations for this function, which has 6 overloads for reshape (https://github.com/numpy/numpy/blob/0066c73f573daafa01cbb975fde7f21d2b045ccb/numpy/_core/fromnumeric.pyi#L189 https://github.com/numpy/numpy/blob/0066c73f573daafa01cbb975...). I don't see a lot of evidence in either of these that the dynamic typing forced people to keep them actually simple. They're filled with edge cases. Compare with Eigen, which uses static typing to separate type parameters from runtime parameters. You don't need to worry about non-integral values because they're unrepresentable. You don't have sentinel values, because AutoSize is a different type with a clear name. The layout is specified as a type parameter, so the order parameter is usable based on information available at compile time. The return type is a bit complicated, but no worse than numpy.
- andersmurphy 1y agoYup, generally less code is easier to maintain so if you can express yourself in an order of magnitude less code its easier to be sure your program obviously has no bugs, rather than it has no obvious bugs. Also most types systems don't go far enough. reverse takes a list and returns a list. That type checks but is of little practical value.