lainchan / λ
Is Object-Oriented Programming bad?
Lady 3Jane.. · 2024-10-19 17:45
I recently stumbled upon this video by Brian Will: https://www.youtube.com/watch?v=QM1iUe6IofM
It seems to make a lot of sense, even to an intermediate beginner like myself, but I'm interested in what you think(USER WAS WARNED FOR THIS POST, You should always elaborate on your opinions rather than just spilling the soykaf.)
Dujour · 2024-10-19 19:16
Bad OOP is a terrible mess. Good OOP is just a mess. Great OOP is okay to work with if everyone on the codebase understands which pitfalls to avoid, when and why to use certain patterns, basic things like inheritance vs composition, how to write APIs that won't make you suicidal, the architecture of the project, etc.
Unfortunately, a stable, nontrivial project of the latter case is, at this time, only theoretical. Scientists estimate we may find one in the next 10 years, but this is what they said 10 years ago, and 10 years before that.
McCarthy · 2024-10-19 21:10
Consider looking at smalltalk before making any opinions on on OO.
The video talks a lot about encapsulation, which is completely unrelated to OO (In fact nothing is "encapsulated" in smalltalk... all messages are public). I do not judge functional languages from Javascript.
https://gtoolkit.com/
I've been using the above smalltalk interface for over a year now and it's made me a stronger programmer as I've delved into many ideas.
Further I recommend reading William Cook's paper about how ADTs and abstract data types differ:
https://www.cs.utexas.edu/~wcook/Drafts/2009/essay.pdf
James K · 2024-10-21 03:47
>>40210
The basis for OO is a message passing system, where many objects interact with each other by passing messages between them. You can see how this is well suited to things such as IPC, or distributed systems. It is not, however, the best way to organise code more generally. Ironically, the union of code and data that OOP touts as a strength is really a weakness. Establishing a contract for code to implement needn't be tied to a specific data structure. You can see this in how many modern languages are moving to separate contracts from data (think traits in Rust, type classes in Haskell, interfaces in Java, etc). Perhaps the biggest benefit of the OO model is for the introspection of dynamic systems, à la Smalltalk. A system of contracts needs an external arbiter to determine and enforce implementation, whereas in OO, an object can be queried as to which methods it implements.
Drifter · 2024-10-21 05:11
>>40210
Smalltalk does OOP in a good way. Everything is an object. Each class can have only single inheritance. The syntax fits on a postcard (no much mental overhead). Try it with Pharo MOOC:
>https://mooc.pharo.org
Other Smalltalk implementations include Dolphin Smalltalk, Cuis Smalltalk (Squeak fork for beginners) and Squeak (Pharo is a fork of it). You can find emulators of historical Smalltalk-80 systems at https://smalltalkzoo.thechm.org
The Squeak site and Pharo site have also some books. The most commonly known Smalltalk books are Smalltalk-80: The Language and its Implementation (the Blue Book) and Inside Smalltalk vol 1 & vol 2.
>https://wiki.squeak.org/squeak/64
>http://stephane.ducasse.free.fr/FreeBooks/
You can get a quick interactive tutorial on some Smalltalk systems (at least Pharo and Dolphin Smalltalk):
1. Open a new workspace or playground inside your Smalltalk
2. Write ProfStef go. 3. Highlight the code.
4. Right click on it and select "Do it".
... Or just try a web browser version at https://amber-lang.net/learn.html
Agent Richard Gill · 2024-10-23 19:19
>>40210
I feel like we get a new variation of this thread once per month...
OOP is a tool, one of many tools in a programmer's toolbox. It's absolutely fantastic for certain things, horribly unfit for others. If you're working on a project that is best expressed in an object oriented way, use a language that emphasizes OOP. Otherwise, use something else.
To digress a bit, I think it's important to know that the compsci industry (along with the tech industry as a whole) is and pretty much always has been very intensely trend driven. A shiny new thing comes along, everyone and his dog wants to us it for literally everything, it turns out that it doesn't make much sense to use the same too for every task, and then, rather than learning from our mistakes, we instead move on to the next thing, laughing at the poor fools who still think the old one has any merit. At one point, OOP was the new thing that any respectable programmer was expected to be an expert on. Now, OOP is the old thing that you're expected to soykaf on as much as possible.
Lady Jessica · 2024-10-25 05:02
oop is a data abstraction technique. there is bad programmers, that for sure.
Koichiro · 2024-10-25 08:34
>>40246
Isnt trend driven everywhere? Fashion is the most prominent example. Trends is just another form of planned obsolescence. You create demand by telling everyone stop using old, you have to use new oh and btw i can do new so buy from me.
If you had a fixed solution you would have nothing to sell so you perpetuate switching whats best.
Lady Jessica · 2024-10-29 15:45
>>40210
>>40246 (me)
I do think I should elaborate on OOP as a programming paradigm though, since that is what you asked, and it's worth discussing regardless. Before we start, I want to make it clear that I'm referring to OOP in the sense most people use the word, which is to say, the Simula-style class-based approach to programming seen in languages like C++ and Java. This will probably upset a lot of Smalltalk fans, but in practice, with the exception of Erlang, nearly every mainstream language claiming object orientation is much closer to Simula than it is Smalltalk, even languages with significant Smalltalk influence like Ruby and Objective C.
In the broad strokes, OO as an approach caught on as much as it did because it aligns well with the way human beings tend to look at things. It's easy to forget if you've been programming for a long time, but thinking of a program as a mostly linear series of instructions that generate and transform data is a surprisingly large conceptual leap for most first-time coders. Our natural tendency is to view the world in terms of objects and their properties, relationships, and interactions, with the sequence of events emerging from that. For example, apples and oranges are both fruits, specifically edible fruits, that both contain nutrients and have flavors, with the specific nutrients and flavors depending on the fruit. If person eats one of them, they will absorb the nutrients, and depending on their preferences, either like or dislike the flavor. OO languages provide direct syntactic support for this kind of thinking, and for problems that genuinely can be described like this, it is far and away the best way to write a computer program. It's why, for instance, gui toolkits are overwhelmingly constructed in such a style, even ones written in non OO languages like C.
The problem is that most problems can't really be described like this, at least not particularly well. Type hierarchies only make sense when the relationships between the types are obvious, and are only helpful when the depth of the hierarchy is relatively shallow. Otherwise, you're adding a ton of complexity to your program for no real gain. And even without type hierarchies, the vast majority of real-world programs are going to have a lot of data that is just data, with no directly associated actions, and actions that can't really be said to rightfully belong to any particular object. The end result is either a) actions and data that have nothing to do with eachother getting attached for no good reason, or b) clunky, roundabout reinventions of imperative and functional techniques a-la utility classes.
With that said, you can get a lot of mileage out of mixing OO features and techniques together with procedural ones, provided you have restraint. Classes provide a great way to implement custom data structures cleanly and efficiently. Virtual functions, for as much as people seem to dislike them, are genuinely a really good approach to certain kinds of run-time polymorphism, and I've implemented them manually multiple times in languages like C that don't provide them out of the box. Hell, even inheritance can be a useful tool for avoiding boilerplate, provided you don't overdo it.
In conclusion, see my initial post. It makes sense that people are moving away from OOP, since it can and has been very easily abused, and it makes sense that newer languages like Go and Rust that very much don't want you to abuse them are either greatly reducing or outright abandoning support for it outright in favor of classical imperative and functional techniques. But at the same time I still think the backlash has been driven much more by trends than it has by the actual technical merits of the OO approach, and many of its opponents don't exactly know why they dislike it, just that they do.
Sorry if that was an incoherent mess btw, I didn't have time to proofread.
Tyrell Wellick · 2024-10-30 15:14
Here goes my dumb question. I unable to install\use javac to test things, so could you explain following:
A java program have Enum of 3 states.
A total function Handler there nearby need to patternmatch, but since there are no patternmatching in java, let's say it takes that Enum as input argument, and use case\if statement on only 2 states. E.g. function is not covering (3rd state).
then in main(), object of Enum initialized with 3rd state. then fun Handler(Enum_object_initialized_with_3rd_state) being called.
...
Does nothing.
Compiles fine.
Error goes silent.
Same behaviour in c++.
whats wrong with compiler, type checker?
are there refined, constrained types & total functions?
James K · 2024-10-30 16:37
>>40284
I'm not sure if you're aware of this sir, but a switch statement in Java simply does nothing if none of the cases match.
Grugbrain Dev · 2024-10-31 12:21
I've programmed in Java many many epochs ago, and recently heard of hard push of Dependent Types.
Meanwhile between those epochs ago & recent advertising marketing campaign of Dependent Types, I mostly used dynamically typed scripting languages & been focused on them.
So, to my naive plain understanding on surface - Dependent Types are types that make operations, calculations on types & produce types ... so, I was like "wait here!... But that's sounds exactly like OOP! Everything is an object aka class"
And to my understanding OOP lang like Java will highlight all those nasty type errors, first during type-check in IDE, then in compile time error.
So ... check-m8 Dependent Types, OOP won?
And in functional langs, we have Type of a Type of all Types. And in OOP we had some sort of "Object Class"?
藤原純一 · 2024-10-31 12:35
>>40280
objective-c and ruby are based on messaging; you are out of your mind if you think those two are closer to Simula.
James K · 2024-10-31 13:17
>>40290
I'm not sure what this is supposed to mean, but the observation I think you're getting at is that an object can be represented by a dependent type ∑o : Type, [C o, o] where C is its class represented as a function of kind * → * defined as ∏ o : Type, [method_1: o → t1, method_2: o → t2 ... ]. This has clear advantages over the object oriented formulation in that the class C is separated from the object it describes. This means you can have classes which describe multiple objects, or objects which implement multiple classes, or even multiple versions of the same class. For instance if you had a class of groups, you could implement it for integers under addition and multiplication.
⍕ · 2024-10-31 14:02
>>40290
Dependent types are just a way to denote provable properties of any kind, they have no overlap with OOP and can coexist with it.
The bog-stadard example of DT is a concatenation function:
concat: left 'a -> right 'a -> result 'a, size result = size left + size right The part after the comma makes it a dependently typed function — it asserts that the size of the result *depends on* the sizes of inputs, hence the result has a Dependent type. If you can write a concat function for List/String/Queue/whatever class in a way that proves this property — you get OOP with Dependent types.
But this rigour is generally impractical, I suggest looking at Design by Contract — essentially the same concept of asserting arbitrary properties, but without the expectation of static provability. A process simply gets fired for violating the contract.
Naomi Nascimento · 2024-10-31 14:34
>>40280
>Type this, Type that...
you have completely misunderstood what OOP is about. It's about getting rid of types in favor of interfaces. You try to talk like a savant but you are an idiot.
Nemissa · 2024-10-31 14:38
>>40293
hey, thank you for answer & attempt to explain.
my problem could be that I've studied insufficiently small amount of Type Theory (outside of Uni) & FP. I can't read notation.
But academia people really made me excited about better expressive safe type systems. So I've been diggin this subject lately.
I've spend slighlty more time learning OOP Java before, but that was long time ago. Most of the time I've spent scripting in dynamically typed langs, without thinking much about types\classes at all, using primitive datastructures & testing for errors in runtime.
object in Java OOP terms are just initialized instance of a Class. It could be initialized with or without parameters.
>∑o : Type, [C o, o]
a sum o : Type, (List of C o.o OvO) ?
>* → *
regex wildcard asterisk, a function that accepts any type and return any type? So a function that acts in polymorhpic dynamic manner?
> ∏ o : Type, [method_1: o → t1, method_2: o → t2 ... ]
I can understand that
here is the confusing part, let me treat you & address as some one who understand FP with (Dependent) Type Theory
>This means you can have classes which describe multiple objects, or objects which implement multiple classes, or even multiple versions of the same class.
In OOP I can have Intefaces, Generics, <Templates> , incapsuled Classes inside Classes, Hierarchy of parent\inherited Classes, also a design pattern like Factory & others that produce new class objects.
FP:OOP score 1:1
> For instance if you had a class of groups, you could implement it for integers under addition and multiplication.
We literally have an Object Class of Integer in Java. We can define Classes, Templates, Interfaces, Generics - type-check & statically analyze them in IDE.
FP:OOP score 2:2
My question is that I REALLY want to buy FP (optionally Dependent) Type Theory and invest money & time studying it, practically applying it's top selling features in functional programming languages, writing expressive applications. But diving deep in to it that's a LOTTA time and very expensive. I don't have a research grant. No one will pay for me & my expenses.
So it's really hard for me to evaluate it's benefits & concepts, without spending years learning it or doing Masters degree in CS.
I'm terribly failing to see (from Dependent Type Theory definitions, explanations) how it is just better & more expressive than OOP for type-checking, static analysis, and catching errors in IDE before runtime. So far for me it seems like on par or equal to what I've been taught in Uni studying OOP.
Can you demonstrate what Idris can do during compile time (type checking stage) that Java can't ?
Proponents of theory also love to bring examples of zipping two vectors together, or implementing a state machine - but it possible to do in OOP & it will typecheck.
James K · 2024-10-31 16:25
>>40297
>a sum o : Type, (List of C o.o OvO) ?
Sum types are the complement to product types. It is a dependent pair where the first element is a type, and the next element is some function of that type. In this case, the next element is a class parameterised on a type and a member of that type. These are also called existential types, as in the dual of "for all".
>regex wildcard asterisk, a function that accepts any type and return any type? So a function that acts in polymorhpic dynamic manner?
This is just the Haskell kind notation. It denotes a function from types to types.
>money & time studying it
Dependent type theory is a very simple concept. It doesn't really take much time to understand if you already know how types work in programming.
>We literally have an Object Class of Integer in Java. We can define Classes, Templates, Interfaces, Generics - type-check & statically analyze them in IDE.
The example I gave was one where the same interface is implemented twice. In Java, this looks like:
<A> abstract class Group {
A identity;
BiFunction<A, A, A> combine;
} Here Group is a class for objects in A. It's essentially what you'd see in the header of an object in the JVM. We can write functions which operate on groups. A function to take the sum of a list is the obvious candidate here.
<T> T sum(Group<T> group, Iterable<T> items) {
T out = group.identity;
for (T t : items)
out = combine(out, t);
return out;
} Then we can get to what I mentioned earlier, that is implementing a group under addition and under multiplication.
Group<Integer> under_addition = new Group(0, (Integer a, Integer b) -> a + b);
Group<Integer> under_multiplication = new Group(1, (Integer a, Integer b) -> a * b);
Group<String> under_append = new Group("", (String a, String b) -> a + b); Calling the previous sum method on a list of these items would take the sum in the first instance, the product in the second, and would join a list of strings in the third. We were able to implement multiple instances of the Group interface, and we could do it to types which weren't defined in the file. In OOP, the person defining the object controls what it implements. In the world of dependant types, the user of an object is free to implement any interface they want.
You may notice that all of this so far is possible in regular Java, but what is missing is the dependant ∑ type from earlier. Suppose we had defined group as a normal interface, we could store a list of them.
interface Group {...}
// Can't do this, but imagine we could.
class Integer extends Group {...} // Only one implementation, not defined by user.
class String extends Group {...}
List<Group> a = {1, 2, "test"}; But we cannot write this for dependent types without a dependant sum.
// Imagine Java had tuples to make this easier.
List<for some <T> (Group <T> group, T t)> a = { (under_addition, 1), (under_multiplication, 2), (under_append, "test") }; This almost looks like something that can be done in vanilla Java, but it can't quite. It's essentially an upgraded form of type erasure. We could imagine the code:
<T> record class AbstractGroup(Group<T> group, T t);
List<AbstractGroup> a = { new AbstractGroup(under_addition, 1), ...(under_multiplication, 2), ...(under_append, "test") }; But this dosen't properly support type checking as type erasure just defaults to filling in Object parameters.
a[1].group.combine(a[0].t, a[2].t); // Should be a type error, but isn't as types are erased to objects.
What's especially notable here is the similarity to the regular Java interfaces. This is because a Class in OOP is just an Object which stores a vtable (function pointers for methods) and some static constants. Then each instance of that object is allocated with a pointer to its class.
// Define a class.
abstract class Example {
int method(int);
} Objects of this class will hold a pointer to an implementation.
class ExampleClass<T> {
BiFunction<T, int, int> method;
} So in dependant typing, you can fully describe the type Example using a depenant pair:
Example == for some <T> (ExampleClass<T>, T)
This is why dependant typing is the superset of OOP. It allows you to describe everything OOP can, without the need for names. Classes, interfaces, implementations; these can all be anonymous and defined at any point in code.
Random · 2024-10-31 21:06
>>40291
ObjC and Ruby definitely owe an absolute fuarrrkton to Smalltalk, don't get me wrong. But the overall structure of a program written in either is going to be much closer to Simula.
null · 2024-11-01 04:00
I'm trying to post an extensive reply, but lainchan just giving me "go away spamer" uninformative message.
synchronized · 2024-11-01 04:20
I dissect in a series of replies
>>40298
A brilliant answer, Sire!
You seem like mastered & perfected understanding of type systems in Java OOP & Functional Programming.
Excuse my peasant level understanding
My Grug logic was more simple, here is an example of a dialogue between functional depentent type theory proponents, lets call em DDT for short and Grug
DDT: Dependent types allow you :
pseudocode
datatype MyType : σ {where σ is in range 34..69} -> Either filtered_σ | ω
overriding · 2024-11-01 04:43
Grug: but OOP can:
Java
//pseudocode
// I had to edit it horrifically, cuz lainchan was rejecting to receive post
Class My_Constrained_Refined_Filtered {
public static My_Constrained_Refined_Filtered(args):
if args in range(34..69):
return self;
else:
thrwExceptn("IDE will force us to handle this case if type argument will be used wrong"); }
My_Constrained_Refined_Filtered(-9000) ;
// or here goes a method that accepts only that class >abstract class Group
after that my brain gone brrrrrrrr, but I tried to read further and understand.
I guess all other popular examples of dependent types were weak, but yours are much better
asyncOverride · 2024-11-01 04:50
>In OOP, the person defining the object controls what it implements. In the world of dependant types, the user of an object is free to implement any interface they want.
I like that good point. I had nighmares from time I found some (poorly supported, abandoned and undocumented) java library I had to use, and the main API method only accepted some Specific Class, and I failed to utilized it, since there was no that SpecificClass definition/description to initialize, and all other arguments were rejected by compiler, with uninformative errormsg "YourArgument is not an of SpecificClass"
Thats why I love dynamic languages, cuz they will not typecheck during compile time, they allow you see how things will perfom, go wrong, fell apart, decay & decompose, see & analyze & learn from mistake, understand the logic of how things work & what could be done .
That's why C/perl/php/python/js/ruby/lisp seem more attractive to me that Rust, Java, Haskell. Easier to understand, read and reason.
So tell me, will you advocate that a pain (& complexity they bear along) of Static Type systems really worth it for 8h/5d while making some e-shops, microservices, especially if compared salary between dynamic/static lang equates in same position. Please kindly tell me, honestly. In 10 years those companies will be bought by bigger ones competitors or FANG, software products ceased to exist. I never worked with a product Dev team bigger than 10 people, despite I switched 10+ big companies/employers.
>So in dependant typing, you can fully describe the type Example using a depenant pair:
>This is why dependant typing is the superset of OOP. It allows you to describe everything OOP can, without the need for names. Classes, interfaces, implementations; these can all be anonymous and defined at any point in code
I can't thank you enough, your explanation with code samples offered a tremedeous help to me. I understood that Dependent Types extend & superset of FP ∧ OOP.
I just need to understad whether the pain & discomfort of :
* learning\adopting\switching to statically typed lang (whether it java/rust/c++/haskell/typescript fp/oop doesn't matter), after more than decade ago I've abandoned Java (with RaRe occasional regrets of not having .intellisense autocompletion in IDE, and occasional rare type errors in interpreted lang, that could be fixed & adjusted easily via editing textfile)
* feel of uselessness , lack of practical application. As I said the apps I work with are small, non critical.
* progers are humans, humans not used to think in types.
* sometimes I think math & type theory are just a new language we invent to ourselves along the way. In other words, it is not discovered to exist in nature, it is artifically invented by humans do describe things & make sense of surroundings.
* 1930s style bootlegging weak dynamic types
James K · 2024-11-01 05:32
>>40305
>Thats why I love dynamic languages, cuz they will not typecheck during compile time
Dynamic languages still have types, they are just informal and underspecified. For instance, in Python:
class Example:
example_field = 2
def takes_example(example):
return example.example_field; Python is one of the more dynamic examples, as it would allow you to call "takes_example" on any object with the correct fields. This is bad as it is a violation of privacy. The contract of the system is not sufficiently specified in code. If the "example_field" is meant to be a private implementation detail, then users' code might break if the name of that field changed.
class Example:
example_value = 2
def takes_example(example):
return example.example_value; You can safely make that change in Java code, as its impossible for other people to access the field. In Python, the writer of the library that implements this function needs to document whether or not the implementation of the Example class is private or public and the user must adhere to that documentation. The main difference between dynamic and static typing is who does the checking. In a dynamic language, the programmer is expected to check the types of functions. In a static language, the process is automated. The price you pay for that automation is that you can only write types in terms the computer understands. Dependant typing has the objective of allowing the computer to understand types in the natural way humans would specify them.
Unsigned · 2024-11-01 06:22
>>40299
interfaces are implemented with classes and methods like smalltalk. objects communicate with messages like smalltalk. neither objc nor ruby are based on virtual tables or prototypes. in simula, a parent method is resolved with a table. in objc and ruby, the message is simply passed to the parent's message handler. for this reason, unlike simula, you don't need to know the type of the object or who are its parents. also, both ruby and objc are based on code blocks like smalltalk.
if · 2024-11-01 16:24
yeah, they kind of have types & classes. and those make my brain go brrr in pain. because I saw some horrible overcomplexity Java code corporate solutions with hierarchy of many many classes, strange relations beetween them, UML diagrams, monstrousity .. so it seemed harder than rocket sciences and required years of onboarding for new employee to learn how it work, and developers worked there for decades, and that was sort of really good for them to keep them on a payroll, and any new problem there solved with just hire and throw more developers at it. But it was also very hard to fix old bugs, unable to changes things cuz it involved rewriting entire logic architecture. So many bugs were unresolved, and many new features weren't added. It was hard to work there & with them. In comparison to python or big shellscript codebases, we maintained later.
So even semi untyped langs (I haven't touched) like C, ASM, Forth do seem attractive to me. All this public static private and type annotation (I do understand their benefits) but for me it's just seem like overcomplicating simple things. I love parsing log files, with sed, grep (bash) even more that with python, but python is fine too. Once upon a time I've needed to parse & sort text data tables in Java, and it took me a week to declare are those classes, functions, types, what could have been done in one line of perl. Static types really slow down development process & not expressive enough as dynamic. And I love interpreted langs more than compiled, with ability to edit code with simple text editor on the fly myself.
I've currently done 25-30% of FP course book with strong static (& dependent) types. And they teach me like everything that I was able to achieve in Dynamic lang with less hustle. and for 1% of selling feautures, idk if I'll ever need or use them. But I have a lot of fuarking ths heat going on around righ now, to make me busy solving other problems that seem more important. I could abandon or postpone indefinetely coursework.
> tell me, will you advocate that a pain (& complexity they bear along) of Static Type systems really worth it for 8h/5d while making some e-shops, microservices, especially if compared salary between dynamic/static lang equates in same position. Please kindly tell me, honestly.
would be nice to hear real world opinion, from mature devs, who need to spend time on wife, family, car maintenance , house rebair\build. e.g. more time on that, practical life, and less time sleeping and nigh dreaming about Abstract Classes Inheritance Interfaces Semigroups monoids endofunctors.
It's like you know, contrary to some one who wrote bad overcompicated hardly usable hard to understand code in Java (or other OOP lang or statically typed FP lang) - that I will struggle, unable to understand\use\fix.
@
I could just use hacky solution, maybe even introspective, reflective, metaprogramming, maybe runtime monkey patching, in python/Lisp. And it will work. And I've seen some hacky solutions in C, implemented by very expirienced programmers in widely used software.
>>40280
I agree. Multiple people said similiar stuff on internet & irl.
>>40246
Idk. Could be. I still holding books on GoF Design Patters, that I haven't mastered nor read whole, due lack of their usage in dynamically typed scripting langs. What is soykaf? OOP was a fancy enforced and thsh!13d trend in 2000, then dynamic langs been on decade rise till 2010, then functional, now it's ai, rust, blockchain, IoT, metaverse, web3.
If Java was just fine, they wouldn't add lambas, closures, other fun features, Scala, Clojure, Jython, Groovy. Similiar trent with ASP NET C#. They felt their lang & platform becoming unatractive, so they made a push to attract new devs, with new tech.
HELIOS · 2024-11-02 07:59
>>40309
You need to use the proper words, mate. C is statically (variables have types that can always be known at compile time) but weakly (stuff can be converted automatically) typed.
> Static types really slow down development process & not expressive enough as dynamic.
It really depends on the scale. Be it the number of people, the duration of your project or its scale, static typing forces documentation of your code, allows for a lot of confidence when refactoring that stuff isn't broken on the other side, etc...
It's true that when you're experimenting or just doing a small script, dynamic typing is a must.
The truth is that you can both have your cake and eat it: it's called gradual typing. Common Lisp has it, Python/mypy now has it with its annotations.
>And I love interpreted langs more than compiled, with ability to edit code with simple text editor on the fly myself.
Same, vocabulary problem. You mean stuff where you don't have to manually compile; Python and Perl are both bytecode compiled, for example.
In my opinion, one big problem of increasingly expressive type systems is that while you're just shifting the processing from runtime to compile time, the syntax isn't keeping up and you almost always end up with something as ugly as C++, especially once meta-programming enters the ring. And the other problem is that programming autists (which I'm part of) often have a hard time not abusing such a powerful toy when they get their hands on it, to the point of encoding most of the business logic in types (i.e. Rust now using it to encode lifetime too; a good GC with optional arenas for sensitive zones has always been the solution to this soykaf).
Just stay with parametric, recursive (G)ADTs, dependent typing and correctly done subtyping (cf variance), don't try to go full ivory tower academic.
James K · 2024-11-02 08:57
>>40310
>The truth is that you can both have your cake and eat it: it's called gradual typing. Common Lisp has it, Python/mypy now has it with its annotations.
These languages can only manage gradual typing because they lack the benefits of static typing. They are the worst, not the best, of both worlds. They can't manage something as simple as a function polymorphic on its return type. In Haskell, you can write:
f :: Num a => Bool -> a
f x = if x then 1 else 0 Which returns a different implementer of the Num interface depending on the requirements of the caller. The can be extended to user-defined number types. It is not possible to write a function such as this without annotations in a dynamic language.
>It's true that when you're experimenting or just doing a small script, dynamic typing is a must.
I don't think this is true. With languages such as Shell or Python, it is library features that allow them to be useful for experimentation. I've no reason to assume that a static language couldn't also have those features. Anecdotally, I've heard many people say that Haskell is a great language for prototyping. Likewise, the only reason stringy-types are needed for scripts is because UNIX enforces a stringy interface on all programs. Shell scripts would be both more reliable, and easier to write if it were possible to do so in a static language. You can see a version of this in much of the Python ecosystem. Many popular Python libraries offer similar functionality to that of a classical UNIX program, but do so with the addition of types (though not type-checking).
string · 2024-11-02 13:21
>>40311
>They are the worst, not the best, of both worlds.
Reread yourself, these language are functionally equivalent to dynamic typing if you don't use any static feature, can't be the worst of the this world.
There's a lot to say about your ML fanboy post, but you realize that your specific example is already handled by dynamic typing, right? Why would you need static typing there, except for better AoT compilation? There's no safety to be gained when the caller automatically forces the return type of the callee.
James K · 2024-11-02 13:43
>>40312
>these language are functionally equivalent to dynamic typing if you don't use any static feature, can't be the worst of the this world
Yes I suppose the feature is very good when you don't use it.
>There's no safety to be gained when the caller automatically forces the return type of the callee
It's not about safety; it's about expressiveness. The type system allows you to express the program you want to write better.
>except for better AoT compilation
While I wouldn't hold this up as one of the greatest benefits to static typing, I find it odd that you're so quick to dismiss it.
>you realize that your specific example is already handled by dynamic typing, right
How? I can't think of any way to do this in CL or Python.
>ML fanboy post
I have very little experience with ML or its derivatives, so I don't think I could call myself fanatical about them.
Ada Savage · 2024-11-02 14:35
>It really depends on the scale.
nah, it doesn't. as >>40309 suggested, write microservices, modules, do one an only one thing at a time but do it well like in small cli GNU utilities, follow 'keep it simple' K.I.S.S. principle .
Types not always self-document code. I've seen some static cryptic, hard to understand, obscure type signatures vs well documented dynamic code.
so, imo, it's kinda ok to use dynamically typed scripting langs, instead of c#/java for most of the e-commerce startups.
Unless you do aviation or medical hardware, but in this case before you knew it you will see some ISO standarts in your face & mandated to use spark ada, compcert, verilog.
>lang prob
Eng is my 3rd lang, among 5-6 human langs in stack. Non braggin, as u can see, me speak them reeliy bed. Also, in last decade, I've seen crazy marketing push for fullstack devs who expected (by HR, tech lead) to be fluent in multiple programming langs. With exponential rise in amount of new langs, Elm, F#, Swift,Go, CoffeScript, Scala, Kotlin, etc etc - I think person able through prime life time 20-25 years master only 1 lang good + frameworks. If they try to claim as many langs, divide quality of the depth of their knowledge by the number of langs.
>CL, mypy
yeah, good stuff maybe, I haven't tried properly, don't have much time to experiment. Sorbet for Ruby, Typed Racket.
>bytecode
yeah, compiled to bytecode pyc, interpreted by vm. [irony]actually java might considered be an interpreted language too.[/sarcasm]
>you have completely misunderstood what OOP is about. It's about getting rid of types in favor of interfaces.
I'd like to have and see more interfaces implementations. BCI
I've seen V E R Y overcomplicated statically typed code written by some Bengal Tigers from Nyanmar. With flowcharts & diagrams can't fit the wall. And this could be true for Java/C#/C++ & statically typed FP langs.
Heard of people getting paid per LoC? Or Leads that see salary growth and are irreplaceble, because no one else in the whole corp understand how business logic implemented in Classes\Objects\Types.
another dimension is when we have to use poorly documented but very important closed source compiled library binary, that exist in single version on this planet, abandoned, and made for some rare thingy\driver etc.
> Many popular Python libraries offer similar functionality to that of a classical UNIX program, but do so with the addition of types (though not type-checking).
some how I feel Shell scripts are more concise & less verbose than Python analague.
James, it added pattern matching recently, and I haven't even caught up with all other functional features it adds. even := . It starts looking more and more like Haskell %) You can be proud & happy.
One day I hope to have a healthier neurons to enjoy applying static fp dail..week..no, monthly could do fine. I wish I could do something good for you, to cheer you up. You inspired me to look at HKT f : <T> -> <T> aka (f :: * -> *) aka (a -> b) -> f a -> f b , at first glance seems complex, but actually simple, I've done that at my recent static FP homework, and in dynamic lang before. (Just seem known as Decorator).
People say static typesystems offloads complexity from brain to compiler, but it seems in dynamic world many of artificially invented problem constraints, limits don't exist.
typesystem of particular lang is just standartized api for tests. and some times desire to reason in those tests, not in the runtime, overcomplicate things.
[code]
Plaintext
//psyduckode
from typing import Callable
import functools
def integer_decorator(func: Callable[[bool], int]) -> Callable[[bool], int]:
@functools.wraps(func)
def wrapper(arg: bool) -> int:
result = func(arg)
if not isinstance(result, int):
raise TypeError(f"Expected int, got {type(result).__name__}")
return result
return wrapper
# Example usage
@integer_decorator
def example_function(arg: bool) -> int:
return 1 if arg else 0
# Running the example function
print(example_function(True)) # Output: 1
print(example_function(False)) # Output: 0
# mypy type checking will succeed if the function arguments and return type are correct
[code]
James K · 2024-11-02 15:30
>>40314
>typesystem of particular lang is just standartized api for tests
This is subtly wrong in a number of important ways. First of all there is a difference between a type system and type checking. Type checking is just a form of testing, it ensures that the constraints of the type system are met. But the type system is the language of types used by programs. For instance, you could create a version of Haskell or Java with the same type system, but the checking turned off. This would defer type errors to runtime. Of course in reality, there is no advantage to doing that. The type systems of those languages are ones for which checking is easy and doesn't restrain code. The critical part of the type system that creates checking is the ability to create closed types. These are types whose members are constrained to the products of their constructors.
Imagine a there are two classes with a single method named "foo". If these were Java classes, each instance of the method foo are different functions. There is a Class1::foo and a Class2::foo. You couldn't call the foo method of a generic object because there is no single foo method. In Python, there is no such thing. Provided the interface is the same, the classes are also the same. If two classes have a method foo, you can call it on either. This is the true meaning of Python being "untyped". All Python classes are members of the same type: a map from string keys to values of any type. An easy way to think of this is in terms of equality. Equality of Python classes is determined by value, whereas Java classes must be reference equal. Python functions are conceptually open; they are defined for all class inputs even if some of those inputs produce errors. Java methods are conceptually closed; they are only defined for inputs of specific types. You can think about this in terms of mathematics. The sine function is defined only on numbers. If I wrote sin(⋄), that is undefined rather than being defined as an error. You simply aren't allowed to write it. It's like dividing by zero; it can't happen.
The true benefit of type systems is that they allow you to create interfaces by declaring and assigning different types to objects. There is a publicly exposed type, and a private implementation type. You then have the guarantee as an implementer that users cannot depend on private features of the library. Likewise, as a user, you know that the only elements of a library exposed to you are those parts which you are allowed to use, so your code will continue to function with any implementation of the interface specified. There isn't going to be a situation where you pass the wrong object to a given function, but it still appears to work because it has the right fields.
>Python code
That doesn't achieve the same thing as the Haskell example. The special thing about the Haskell code is that Num is an interfaces which users can implement. So you can call that function and have it return an int32, or a complex number, or any other implementation of the generic Num interface. This behaviour is inferred from the types present at the call site.
↑ · 2024-11-03 12:24
An object is data abstraction technique that hide the said data behind a set of operations (the interface). no more reasoning with data or types but now with interfaces, it enables all kind of interface abstraction techniques known as design patterns. An alternative data abstraction technique is the abstract data type. Both object and ADT have advantages and disadvantages known as the ROW vs COLUMN decomposition.
I have studied PLT.
This paper will give you a quick rundown:
https://www.cs.utexas.edu/~wcook/papers/OOPvsADT/CookOOPvsADT90.pdf
dup · 2024-11-04 13:17
From what I understand, in Simula OO, the approach most statically typed languages take, an object is basically a struct with function pointers, and maybe some extra indirection depending on the language. Smalltalk OO is kind of like the inverse. An object is like a lambda that contains static-ish variables that maintain their state between invocations, with methods being code branches that are taken based on the arguments provided to the function. If you want to be pure, you can make the semantics of your language deal in nothing but these functions, with primitive types only accessible behind the wall of intrinsics. There's also other approaches, like Go's interfaces and Lisp's multiple dispatch, but I don't really know how those work.
Did I get anything wrong?