-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Why typeclasses? #30
Comments
I think the question is why not just pass all the interfaces as arguments? You can of course do this, after all type classes are implemented as implicit dictionary arguments. The advantage of type classes is that they are implicit, hence you have shorter more readable function signatures. They can also be inferred, so you don't have to explicitly type the constraints. You don't want to have to explicitly thread |
Thanks for the reply. I appreciate those advantages. I am just thinking about near-term priorities. I think achieving the "perfect" language is a major endeavor that needs a significant amount of funding and time. I've been thinking that your goal is maximum genericity (i.e. the ability to write some code that can parametrized over many types and uses cases) and minimum explicitness (although in other cases you argue for more explicitness where I argue for less). My near-term goal is not that. That is far too much for me to think about and digest at this point. I am wanting some improvements on JavaScript so I can go use the same code base both on the client and the (Node.js) server. For example a cryptographic library.
I've been thinking about achieving a much simpler transpiler to TypeScript that can meet those near-term objectives. Later can experiment with moving to higher levels of genericity and less explicitness, if warranted by the use cases that are prominent. And with more funding and momentum behind the initial simpler transpiler.
That works if you only allow every data type to implemented only one way for each typeclasses, but as we discussed in the past (with @skaller) that has limitations also. Otherwise, you could get unintended implicit functionality. So explicitly passing has its benefits. Edit: Dec. 4, 2017
|
Regarding one implementation per class, that is the advantage of type classes :-) If you want more you need to pass an object or function (because you want the implementation to depend on the value of the object not the type). To me it seems you can do nearly everything you want in typescript, so why not use it? I am working on a project in typescript at the moment, and for the ES6 stuff plus types it's good enough. Regarding goals, I agree maximum genericity is my goal, and minimum boilerplate. However I also want to prioritise readability and understandability over conciseness, as you spend more time debugging and maintaining code than we do writing it. However I am happy for explicitness to be optional, which includes type-inference (type annotations optional) typeclass constraint inference (so constraints/bounds are optional). The only place we need types would be modules, where we want a stable interface that enables separate compilation. |
If one universal implementation for each universal class was an absolute advantage or even feasible, then we wouldn't need scoping for (type) name conflicts in programming. It is impossible to guarantee one global implementation for the universe, because total orders don't exist. I am not arguing that it can not be a feature that is desirable in some cases in a partial order.
I guess you didn't read my list above, or didn't realize that the items I listed which TypeScript doesn't do are extremely important for the work I need to do.
Ditto myself. I take this even further than you as I am thinking all types shall be explicitly declared, except in an assignment where either the destination or source is explicit, but not required for both. Since passing function arguments is assignment, then anonymous lambda functions can be implicitly typed by the function's argument type. |
I thought typescript included ES6 features, and has integer types as well as strucures (classes). The only one it does not have is "everything is an expression" I think, so it seems close to what you want? Regarding type classes, it is clear that each function can only have one implementation for any given set of argument types. In other words we can only define one implementation for |
Disagree (and my reason was already stated). But I don't want to repeat that argument now. I have said all I want to say about it for now. It isn't a priority issue for me at the moment. We can revisit that later if ever get to the point where I want to implement a "typeclass" language. Edit: we had a long discussion about this in another thread in 2016. |
Afaik, there are no integer types in ES6. Are you thinking of 64-bit math methods in ESNEXT? http://kangax.github.io/compat-table/esnext/ Interfaces and classes do not pack into http://wiki.ecmascript.org/doku.php?id=harmony:typed_objects In 2016, I wrote some very complex (untested) JavaScript code to improve on that concept and provide a polyfill. But it has some drawbacks. I need to revisit that code to refresh my memory. |
I looked again at Nim, but it is getting too far from JavaScript (wants to be a systems language competing with C, C++, Rust, and Go). For example, lose JavaScript's And it doesn't offer 64-bit integer support on JavaScript. And I'd much prefer the JavaScript output is recognizeable, so the JavaScript debugger can be effectively used. |
I think I envision a robust way to transpile from a syntax and type system I want into comprehensible TypeScript. For example, I can use TypeScript's getters and setters to access the fields by name of a |
It may be slower than normal JS objects due to packing issues, or it may be faster due to non-string property lookup. It certainly seems the right way to process binary network data, but I would probably use native JS objects everywhere memory layout is not important. |
Agreed. I didn't intend to imply otherwise. Not only network data, but file data. You know I am working a blockchain design. Edit: Also memory data. With a blockchain, you need the UXTO stored in RAM and this becomes huge. |
nodejs can mmap files from JavaScipt which would work well with this too. You don't have too many choices in-browser, you are limited to Blobs with a streaming interface, and the file IO API is not supported by all browsers. |
Right agreed. Interacting with binary data in JavaScript on Node.js is via very verbose APIs. I'd prefer a language native solution. |
I wrote "client side" but that doesn't mean we are limited to the browser. I am thinking Android and iOS. |
Most in the blockchain realm use a systems programming language with good binary control, such as C or C++. But this is painful in other aspects. There is a lot of verbosity that isn't always needed. Need complex libraries such as Boost for asynchrony, etc... Do not have GC by default, etc.. I think it is overkill. I am searching for a better balance. Rapid coding with less needless verbosity, yet still be able to handle binary data and integer math without verbose APIs. And also some (explicit) typing for correctness checks and better readability (open source). |
Others have integrated C/C++ with JavaScript via Emscripten separating out code that requires that control from that can be done more elegantly in JavaScript, but this IMO isn't ideal. Most code doesn't need to be that heavily optimized (or at least not the first priority). I am thinking there should be something in between a toy language such as JavaScript and a full blown systems language such as C++. |
node-webkit could be an option then (npm nw). You can still compile typescript ( for example: https://basarat.gitbooks.io/typescript/content/docs/quick/nodejs.html ) |
Good point and agreed if Node.js APIs are needed client-side. |
Well if you want to read and write binary files, its pretty much required. In a browser, FileReader ( http://caniuse.com/#search=FileReader ) is well supported, but FileWriter is not ( http://caniuse.com/#search=FileWriter ). |
Obviously Node.js isn't the only way to read and write files on Android and iOS (and even can access it via JavaScript in a WebBrowser instance). Whether one wants to carry all the baggage of node-webkit just for file APIs is not a certainty. But yeah, it is apparently one of the options. |
My focus in on the notion that we shouldn't be forced to use a systems language just to do integer operations and packed binary structures. That we should be able to combine these capabilities with a rapid-coding paradigm that has GC, simple-as-pie asynchronous programming, and less optimum but less painful ways to for example manipulate strings (because we don't always need that to be highly optimized). C++ is too tedious and overly detailed when in most cases we don't need that. Yet we shouldn't have to revert to C/C++ just to get integer operations and packed binary structures. Premature optimization often means projects that don't get finished. |
Yeah performance is battery life and that is important on mobile. But projects that get to market are more important than projects which don't. |
For Android and iOS there are things like Cordova, is that the sort of thing you are thinking about? |
Yeah there are also Nativescript and Tabrisjs. But I am not sure if I choose those, because may also want to think about desktop apps as well. This is a wide open field of experimentation, because we also have convergence of the laptop/desktop and mobile on the horizon perhaps... |
Using HTML5, JavaScipt and IndexedDB you can already write software that runs across mobile, pad, laptop, desktop, and big-TVs. It works pretty well, except for annoying corner cases, like iOS limiting IndexedDB to 50MB of storage. It's definitely fast enough for a lot of applications, and HTML/CSS makes good looking UI reasonably easy. |
Writing to the least common denominator controlled by gatekeepers who squat on and stall innovation seems to me to be a losing paradigm. What about SD cards, cameras, various multi-touch swipe gestures, etc... Consumers care about features not about how you achieved it. |
Well you have to write your own "drivers" for each platform. On Android you have to write in Java to call all the native APIs, but you can call Java you have written from JavaScript if you create an android application shell in Java. Same for iOS (9+) where you can call native APIs from objective-c or Swift, and you can call your own objective-c or Swift code from JavaScript, so you would need a different objective-c or Swift wrapper app. These wrapper apps need to get into the respective app-stores, which means getting Google/Apple to approve your code. You can distribute outside of the app store on both devices, but it requires the user to jump through hoops (android you need to enable a device setting to allow non-app-store apps to install, iOS you need to "trust" the developer of each non-app-store app in the device settings). |
Agreed and I was fully aware of that. But good you've summarized for readers.
These companies are trying to create walled gardens and be gatekeepers. Me thinks the free market is going to route around these Coasian costs. They are trying to carefully position themselves with "safety" and "convenience" to acquire monopoly control. In fact, that is one of my other longer-term goals. If you have an open source app which acts as a base for all other apps and doesn't abuse as a gatekeeper, then it could alleviate this problem. Once everyone has that base app installed, then it takes care of overriding all these toll bridges. Toll because the costs are paid but indirectly.
Clicking Ok for a confirmation dialog is not problem for users. It is when they make the enabling action modal and hidden, that the achieve insidious control. Popping up a red alert, "many other users have reported issues with this app" (with a link off to details) would be a sufficient free market solution to safety. Even Google realizes that ads can't sustain the company. So they are going to have to become monopolistic. Open source should slay this, as it did to Microsoft Windows. Android defeated iOS in global installed units (not dollar weighted) marketshare because it was more open. Ditto to Android if they make it difficult for users to have freedom. As I assume you know, Android still lags (or perhaps near parity with) iOS on a dollar weighted basis (such as $ spent on apps), because iOS simply worked better. For example the egregious latency with Android audio was unacceptable for some scenarios and many people aren't even aware of issues like this. Apple's cathedral-style engineering integration was superior, but eventually bazaar-style open source catches up. Takes a while. |
@keean I am not actively coding again yet (only the 19th day of my 8 week intensive 4-drug phase of TB treatment) I find this comment to be relevant:
And the comments complaining about the JavaScript ecosystem chaos such as this one:
|
And as I had pointed out on the Rust forum back in 2016, all the complexity doesn't really provide us anything that really helps us that much because most programming errors are not constrained to the sort of safety Rust is checking for (yet those safety checks are very debilitating to code in), as reiterated by this comment:
|
@shelby3 You can be not afraid to offend socialists, and I agree that analysing the reasons some projects fail could be relevant, although probably better in a project management topic. However I think you are going too far in shifting this towards a discussion of the virus, or economics. The danger is other people with differing views will start to engage on these topics, and the actual PL stuff will get lost in the noise. I think you could have made your point perfectly well without needing to mention those other topics. Now I am going off-topic and adding noise to the discussion too. Let's try and get back on-topic. |
@keean - I am concerned with the attitude that one has to accept a particular (abrasive or indifferent) mindset in order to be a welcome contributor. @shelby3 edited out some particularly strongly-worded off-topic stuff (that some people may have found offensive) but not, critically, the attitude that dismisses working with people who dislike said stuff. However, I accept that this isn't a personal project of his. I'll simply refrain from engaging with him. I'm happy to work with people with all sorts of different views, or to not know what their views are, in order to accomplish something worthwhile, as long as they'll do the same. Shelby's indicated that's not really how he views things, which is up to him, but who I interact directly with is up to me. ( Edit--I see in another comment you've ascribed to me positions I don't hold. There's a very big difference between saying that under no circumstances can you offend someone and going out of your way to bring up topics that commonly cause contention and offense. Maybe my view is clear now, maybe not, but I'm not holding you to anything so I don't see a good case to keep talking about it.) I will be on-topic from here on when I post, save for very brief clarifications if my off-topic stuff has been misunderstood in a problematic way. |
@keean - I'm not familiar with Agda's implicit typeclass scheme, but Scala does it this way also--if you want to use a different ordering, you just pass in a different The problem with Scala's scheme is that without global coherence there may be multiple implicit typeclasses in scope that could be relevant, but clearly some of them make much more sense than others. Knowing where to look for implicits, and letting the compiler make the obvious choice when more than one is in scope, and making what is obvious to one programmer discoverable by other programmers, has been a source of considerable pain for Scala developers. We've mostly borne the pain cheerfully because of the incredible utility one gets in return, but there are improvements there too in Scala 3 (too technically detailed for me to care to get into them, but you can read about the entire reimagined implicit-and-typeclass scheme[https://dotty.epfl.ch/docs/reference/contextual/motivation.html](here, starting at The New Design about halfway down). Though I have some quibbles with some details, overall I think it's a substantial improvement.) Having used both Rust and Scala extensively at this point, I must say I considerably prefer even the Scala 2 approach over Rust's. Rust interfaces are littered with "Oops, what if I don't want the default implementation?" methods for sorting or whatever. Of the two scenarios, being able to get custom functionality when you're using typeclasses, at the expense of some difficulty with finding the right one in certain obvious cases, seems much better to me in practice. Rust's solution (newtyping) works okay if the thing is a bare type, but when it's a generic type parameter, you can very easily run into major runtime performance penalties in addition to the tedious boilerplate. It's possible that with sufficiently different language features that there could be no downside to a flexible scheme like Scala's, or no need for anything but global uniqueness. The extant examples have downsides both ways, though. And while I find Haskell not to my liking, plenty of people do and don't seem particularly bothered by uniqueness constraints, so I can't make a strong claim that my preferences are universally shared. But hopefully I've explained why my preferences are what they are. |
@Ichoran I have no way to message you privately, so I will just have to put this in public. I want you to know that I appreciate very much your interaction and the contribution you have made to the brainstorming process in the various issues threads here. I am tolerant of your criticism. No harm. Nothing significant was censored. I understand your viewpoint that you would prefer to have a purely technological discussion and never mention organizational culture. I understand you would prefer I change my habits at times when necessary to avoid creating tension. I understand you want harmony and production as a highest priority. Seemingly all admirable stances. At this stage I think my priority is on frank discussion of truths, not on building community. Because right now at the earliest stage, any mistakes in design and/or planned organizational structure could be critical mistakes. Community comes later and really isn’t relevant right now. At the community stage, I might be kicked out, lol. I usually am. I happen to believe that sometimes being unpopular is synonymous with being unafraid to discuss frankly. Anyway at least everyone knows I will not be involved in any project that has an organizational structure like Rust with its Baskin-Robbins 31 flavors of leaderless organization. Or JavaScript and its 400,000 libraries. One of the main criticisms against both ecosystems is the lack of stability and official libraries. It’s chaos. EDIT: I learned from when I created WordUp in the late 1980s which garnished ~30% marketshare of the AtariST word processor market and CoolPage(.com) in the late 1990s that garnished ~1% share of the entire Internet by the turn of the century, that building community is about making things easy-to-use. And since then with my involvement in the cryptocurrency ecosystem I have learned that enabling rampant speculation is the sure-fire way to onboard. Everyone loves a good Ponzi scheme. Think MLM and Amway, which spread like viruses. Building community is not some admirable thing — it’s manipulation of the sheepeople. I like Trilema in the sense that he’s a realist and calls a spade a spade. Socialists are liars who pretend everything is admirable whilst they’re manipulating the situation or are “useful idiots” who are clueless about what they’re really propagating. EDIT#2: another way to make things popular and onboard a large community is to make them addictive such as Tetris, Farmville, or upsizing soft drinks with increased concentrations of high fructose corn syrup and caffeine. The Story of Tetris | Gaming Historian Community building is about manipulating the dopamine receptors (pleasure centers) of the neurological system and appealing to the ancestral hindbrain. EDIT#3: I think the main discord that comes later in community building a burgeoning PL ecosystem is due to impossibility of being able to make a PL that fulfills every use case perfectly. And then tension about imperfect tradeoffs and subjective issues. At that point, unlike others who argue to discourage forking and splitting the community, I would be of the opinion that may the best fork win. I think I would be a leader who will listen to all views and then try to make sure they are elucidated coherently so that we’re all clear on the tradeoffs. Then if I were a leader, I would make a decision. I would not put it up for a vote. I would let people vote with their feet. Anyway, that’s how I would run a project. And I would never allow a CoC on my project or fork. If someone is being disruptive to the point of filling threads with endless off-topic noise, I would simply make sure I have platform which enables me to press “filter” and anyone who wants to use my filter is free to do so. IOW, decentralized curation. No one is 100% censored, but yet we can squelch the noise. Win-win. I am eager to implement this. And thus eager to finish this PL so I can get on with programming. Well I would use a vote if I was ambivalent about a decision that seemed to have no clear objective choice. EDIT#4: the other way to make something popular is to scare people. Fight-or-flight is a primordial urge of humans, which this current virus phenomenon exemplifies. Imagine that a virus which kills 0.001% of the population can cause humans to shut down 30% of their GDP and launch the onset of severe economic deprivation due to Minsky Moment deleveraging and the chaos that results from initial economic distress. EDIT#5: I actually did not read @Ichoran’s messages from today before I wrote the above. So now I want to respond to this bit:
Conflating criticism of an ideology with emotions is not astute. Criticism of ideology is not ad-hominem.
That’s totalitarian-speak. You will need a 1984 thought-police to fill the power vacuum of CoC since nobody can quite agree on exactly what is correct behavior. Your “concern” is that you can’t control the behavior of others. That is intolerant browbeating in an attempt to disguise it as virtuous. I am criticizing your ideology also. I refuse to join a project where people can’t speak freely. Those who get offended are the ones who can’t separate their emotions from meaningful decisions about substance. I suppose you find some value to the Rust project and perhaps perceive my strong opinions about it to be arrogant. I think Rust is a move backwards and it is useful for exemplifying what not to do. I don’t know if there is any feature I would want to take from Rust. I think I have learned nothing at all from the project other than what I do not want to do (with a possible exception for the crates design) — although thinking about how I do not want a total program order on data race safety helped push me towards Actor-like partitions so I guess Rust did influence me in an important way but in the negative sense. And nearly ditto for JavaScript, except that I recognize it was a necessary evolutionary transition and it demonstrates the importance of simplicity and zero compile-time. I will repeat that I think technologically Rust will fail because it attempted to merge high-level and low-level programming (in addition to the organizational reason I think it will fail). [EDIT: note how much slower Go is on benchmarks because it doesn’t attempt to be pedantic about low-level performance and create a clusterfuck of complexity with the high-level features — which are admittedly also spartan] And I am observing that mistake and deciding instead to focus on the high-level and only add the ability to share binary packed data with the low-level FFI. Scala was a big leap and learning experience for me which is much appreciated. But I have by now come to realize that Scala is not principled. It’s a kitchen-sink language, e.g. OOP, subclassing, implicit conversions, and type classes. Learning about Pony (thanks to @Ichoran for telling me about it) was also very important in the development of the design I have so far, because it caused me to think about Actor-like partitions versus green threads versus Rust and the GC and data race safety issues. I think I have devised something better than both of Go and Pony in theory. We’ll see... |
@shelby3 - Organizational culture can be discussed on an issue devoted to such. I think such conversations are beneficial for a project if conducted calmly and with evidence or at least careful argumentation to back up all points. |
@shelby wrote (replying to myself again):
The paradigm was Typestate. Here’s some links I found about that history:
I found the following comment from the original Rust creator to be illustrative of my point about all that lifetimes borrowing, total ordering tsuris in Rust being not worth it:
Also I recall the discussion with @jdh30 wherein he argued that Rust’s so called zero cost abstraction is not even from a GC standpoint when cost of real world algorithms is considered. EDIT: ironically one of the early goals was concurrency, yet Rust still doesn’t have a stable concurrency story: https://www.infoq.com/news/2012/08/Interview-Rust/ EDIT#2: I am correct that the main impetus for Rust is the power vacuum created by C++’s design-by-committee morass:
Here’s my current thought process on that which I sort of already outlined upthread. I explained this to @keean in a private message yesterday. I want TypeScript but with sized and unsigned integer types, binary packed structures and retain references. So a reference is just an ID. No references to references. And you can not reference a primitive type (a reference is also a primitive type). Thus binary compatible with a low-level language for when you want to twiddle the bits. C might be just fine. Then do all our high-level programming in the high-level language. Only a very small percent of your code needs low-level optimization. Use a profiler. Work smarter. I also want to add type classes and remove OOP. And I want to add a concurrency paradigm which is sort of the best of Pony and Go combined which I have named ALP = Actor Like Partition. So compatible with green threads or EDIT#3: I think perhaps the culture of Mozilla which is intent on making it as safety oriented as possible to gain marketshare (thus the we-know-better-than-thou-culture) was driven from a goal to displace Windows as the monopoly (but it morphed into a Frankenstein):
I was thinking that yesterday and now reading the above I gained some confirmation. |
An essential fault appears to remain in Scala 3’s implementation of type classes. That is AFAIK the implicit resolution is not transitively turtles down the call hierarchical according to the function hierarchy? So you can apparently end up with inconsistent implicits in the call hierarchy if you inject an instance as an argument but some place else in the call hierarchy an implicit is resolved implicitly to a different instance? AFAICS my technological proposal avoids that design error. (oh but remember according to you, I am not capable of making technological contributions here, lol)
And yet you criticize my generative essence hypothesis for why Rust is the way it is. And criticize me for expressing it. And equate that analysis with a lack of control over my emotions, lol. 😆 I guess you did not even appreciate that upthread recently I was defending your arguments in a couple of instances where I thought @keean was not fully appreciating your points. Yet I am the arrogant one. 🚔 👮 If you only knew that I was writing in a very amicable tone about you yesterday in a private message to @keean. That I appreciate and value you and unfortunate if you would leave. The problem it seems is you are intolerant of strong derogatory opinions about projects or ideologies — I am not criticizing individuals. I cited individuals only as examples where they exemplify an ideology to support my hypothesis of an overriding ideology at an organization.
And I posit will be even better with my proposal for partial orders. But maybe I have missed some key points that will only become evident later and bust my bubble of optimism.
Pita.
It seems there could at least be more flexibility in choosing the tradeoff between how coarsely grained the implicit total ordering and how much explicitness one wants. I wrote that upthread already in my response to @andrewcmyers yesterday. @keean I think @Ichoran makes a very important implicit point here. Rust may end up giving type classes a bad reputation. We need to hurry up if we think we can do better before type classes become spurned.
I don’t want Haskell. Haskell is principled on equational reasoning, pure FP with type classes. I prefer an imperative paradigm because I think of programs as an execution order not as an equational model. Math doesn’t have state, the real world does. |
@shelby3 Rust is doing okay, it's the most loved programming language: https://appetiser.com.au/blog/the-most-loved-and-hated-programming-languages-according-to-developers |
Don’t believe everything you read. Note Scala was one of the most disliked PLs on their survey. Python and TypeScript seem to have the highest combined rankings of Most Popular and Most Loved, which concurs with the PL design I want to create (combining syntax features of Python and transpiling to TypeScript). Go and Swift are in the next tier for both Most Popular and Most Loved. (Also in the SO survey I see that most people do not contribute much if at all to open source, so reliance on community is overrated. @keean our age bracket is only 3 – 4% of programmers.) There’s a lot of hype and propaganda causing people to maybe be interested in Rust but let’s wait until they experience the pain points…which for people coming from C++ might be tolerable but probably/perhaps not those coming from Scala or other decent high-level language such as Python. Rust will continue to have a market until someone makes a better high-level language that integrates with a better C. If someone creates that (and I’d like to but I won’t say I will because old and unhealthy), then I think Rust may lose its luster. Also Go may improve as well interim which may cannabalize interest in Rust. I would be delighted if someone else would create the PL I want. But I been waiting for ~10 years so I am not very hopeful that anyone else will. I also think that is the problem with C++ is that it tried to be “Most loved” is apparently not synonymous with ‘most used’: https://www.zdnet.com/article/developers-love-rust-programming-language-heres-why/
[…]
[…]
Brave defies Google's moves to cripple ad-blocking with new 69x faster Rust engine:
[…]
Oh so let’s dig into the details of that lie: https://brave.com/improved-ad-blocker-performance/
|
EDIT: Perhaps the most important insight I learned from the following endeavor was that Microsoft schemed to keep JavaScript as limited as possible so that it would not complete with C# and .Net. And even to this day the marching orders for TypeScript is that it is only “a syntactic sugar for JavaScript” being also a superset of ES2015 (formerly ES6) and must not introduce exotic features which do not transpile more or less intact, including apparently the highly requested higher-kinded typing feature aka for F-bounded polymorphism, c.f. also. This is what has opened the opportunity for someone like us to build on top of TypeScript or ES2015 features that “should” have been there a long time ago. IMO, this is why Scala.js is so popular. I mean features that serious programmers have wanted for a decade or more. Reading Brendan Eich’s historical account.
|
@shelby3 wrote:
The problem with C++ is that it eats anything what smells like a feature. |
Does anyone really like teamwork? Gavin McInnes at TEDxBrooklyn ← funny
[…]
Note he did not mention mutual defense. That requires teamwork and is essential to surviving periodic societalcide. |
@sighoya wrote:
Yeah but I think my point remains. They add those features for low-level performance optimizations or high-level programming capabilities, because they want to be both a low-level performant and a high-level PL. I know you all know the following but I will explain for other future readers. Yet attempting to be both makes it more complex to excel at either end of the spectrum. Firstly the humorous but sordid tale, C++ Frequently Questioned Answers:
One example is pointer arithmetic which is enables low-level optimizations in some cases yet at the high-level it breaks encapsulation which prevents buffer overruns. Another example for C++ is the concept of r-values and all the optimization complexity to prevent copying of return values: https://en.wikipedia.org/wiki/Copy_elision#Return_value_optimization Then the complexity of the corner cases where it doesn’t work: https://www.linkedin.com/pulse/c-return-value-optimization-dipanjan-das-roy/ So we can sort of emulate type classes with templates but without the implicit functionality: https://functionalcpp.wordpress.com/2013/08/16/type-classes/ Yet templates are Turing-complete so we end up with template metaprogramming which makes it unpredictable what templates even do, i.e. you have to run the compile to see if they even halt or if they resolve in a predictable manner as you refactor code for maintenance and new features. AFAICS, the complexity clusterfuck is significantly due to the goal of trying to merge high-level and low-level. I’ve read that even the creator of C++ doesn’t understand all of the language thoroughly. I used C++ to code CoolPage and Art-o-matic around the turn of the century but that was before much of the complexity became mainstream such as heavy use of template programming and the Boost libraries, etc.. I thus never learned all that. I essentially stopped using C++ when I halted all development of those applications circa 2003. I transitioned to JavaScript, PHP, ActionScript, HaXe, then directly Scala on the tip from @jdegoes (entirely skipping learning anything about Java). Before C++ I was highly expert with C and Intel and Motorola assembly. Learning Scala exposed me to Haskell, which I resisted because it was so foreign to me given I had done low-level imperative programming since age 13 starting from Apple II BASIC (or let’s say it made my head hurt because I didn’t get it and nobody was explaining it circa 2009 in a way that would click for me). I wrote much of WordUp in the late 1980s in 68000 assembly until I discovered C. Then I went on a tear with my new found productivity with C producing WordUp 3.0 (together with my employee/colleague Mike Fulton) before burning out. I remember consuming the K&R C book afair in one evening and being on a programming tear the next morning. C just made sense to me coming from assembler because I had consumed a Radio Shack book on Microprocessors at age 13 when I was laid up in bed from a high ankle sprain from football with nothing else to do. So I was coming into programming from a desire to want to understand how the hardware functioned. I enrolled at the University to pursue BSEE with a math minor but dropped out when I was spending 10+ hours a day in the library doing my own research and programming at night leaving nearly no time for studying given I was also heavily in drinking and sports. Up until my 3rd year, I maintained a 4.0 GPA by not attending classes and cramming on the night before exams. I’m not a Rust expert having not used it to write any code (other than maybe a few toy snippets). I’ve read the documentation and read a considerable amount of expert discussion (from both sides including the defenses from the Rust fanboys[1]). Rust seems to have many cases where the desire for both high-level and low-level features create complexity that wouldn’t be the case if it has just focused on being a data race safety and “zero-cost abstraction” low-level language. For example the complexity around closures which @keean raised. Others such as the Rust discussion I cited up-thread have enumerated other examples. Again I will reiterate that Rust seems to be an improvement over C++ complexity, at least if total program order lifetime borrowing is not factored in, but they can’t be factored out as that is the essential USP for Rust. Rust is only slightly more performant on benchmarks than C/C++, yet it is considerably more performant than Go: https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/rust.html I might be interested in a low-level PL that stripped out the type classes, closures and all the obfuscating, implicit conversions cuteness from Rust and focused on being a faster and more safe C. If Rust had focused on something I really need, I might be a fan. But as it stands right now I do not need the tsuris of Rust for high-level programming. And I don’t need for low-level programming, the complexity of Rust’s ecosystem and high-level conflation. I want the next low-level language I will master after C to be stable and hyper-focused on seamless integration (without FFI marshalling overhead) with whichever high-level PL has formed a market Schelling point. For example I might be willing to tolerate the lifetime borrowing complexities and annotation noise (given the apparent improvement in performance and some safety guarantees is provides) if there wasn’t the conflation with the high-level feature of type parameter polymorphism (aka generics). A low-level language doesn’t need type parametrisation. I suppose after creating a high-level programming language then I need to tackle creating a fork of Rust and new low-level focused PL. Ha. Dreaming, if I was only 25 years old again I could possibly do that. No chance of that anymore. 🌔 Does anyone else have a different perspective? [1] Intelligent guys who make intelligent technical arguments, but they miss the big picture point. They are so religiously attached to the notion that Rust is some hypersonic, hypersafe killer app that will soon conquer the world. And that unrealistic (“aspirational class”) ambition colors and feeds their confirmation bias blindspot — the world doesn’t need a conflation of high-level ease with low-level performance resulting in a complex Frankenstein pita. |
Looking at this with a clearer mind and more sleep and ignoring the white paper and focusing solely on the code examples on the JMatch homepage:
I don’t know if there is additional significance or novelty to your work, because I have not tried again to digest the research paper. I do agree with the utility of these features and would be interested to explore them. |
I think you're getting the gist of it. Pattern matching can be viewed as a kind of reverse-mode computation in which values are deconstructed instead of constructed. JMatch allows any method to declare reverse modes that can be used to pattern-match (one or more times) against a set of arguments. What it means to match can be specified with a logical formula, so pattern-matching is not tied to the concrete representation of values as in Haskell, OCaml, etc. |
@keean, so your idea is likewise for records. data MyStructInstance = MyStructInstance
class struct StructInstance where
assocType A
assocType B
a :: A
b :: B
instance struct MyStructInstance where
A=Int
B=Float
a=2
b=3.0
-- Generic Typeclass Bound
fun :: struct s => s -> s.B
fun s = s.b
-- Trait Object
data TraitObject = forall s. (struct s) => TraitObject s
fun :: [TraitObject] -> TraitObject
fun = ts = ts!!0 All this kind of stuff can then be generated with normal record like syntactic sugar: data struct A B = struct {fieldA::A, fieldB::B} |
The creator of Node.js has created Deno to correct the accumulated crud in Node.js. He remarks that Go is a more performant PL for a server but the JavaScript server still has some valid use cases (e.g. sand boxed): https://youtu.be/M3BM9TB-8yA?t=174 Ryan Dahl mentions the clusterfuck of module importing, Ryan loves TypeScript, which furthers my expectation that an improvement on TypeScript would be popular. The Node.js replacement Deno is advocating Rust as the low-level language for the (probably much) less than ~20% (i.e. Pareto principle aka power-law distribution of resources) of your code that needs to be fast. https://youtu.be/1gIiZfSbEAE?t=723 Yet the rudimentary integration across the FFI is apparently not mutually typed: https://youtu.be/HjdJzNoT_qg?t=1379 They’ve coded the entire Deno executable in Rust, but that’s understandable given all of it needs to be fast given it is a system layer. Their mainstream options were essentially C++ or Rust, so it makes sense they chose Rust per my prior comments in this thread. But for the majority of users who just want to code some lower-level subroutines in a high performance, low-level PL, then the conflation of higher-level Rust features with the lower-level requirements, adds unnecessary complexity and unsoundness. EDIT: indeed I was correct that Ryan considered C++ as the other option: https://youtu.be/M3BM9TB-8yA?t=1406 My current priority (if I can get healthy enough to consistently think clearly) is to improve upon TypeScript for the high-level language part. Again Scala was a breath of fresh air for me and a significant improvement over what I had used before it. But then I ran into the aforementioned issues of its non-principled, “kitchen-sink” design (being a jack of all trades and not hyperfocused on a superior paradigm, removal of implicit conversions, simpler and more sound type system, etc), and Scala's lack of unsigned and sized integers, lack of non-disjoint, structural (aka anonymous) unions (Scala 3 adds these), the crap concurrency support with inability of Scala.js to integrate with Pony is/was an experimental PL that provided some interesting insights into what is and isn't needed for an Actor-like partitions (ALP) paradigm, but I posit it’s not the right design and will very likely die on the vine. Sorry to be so frank and overtly opinionated, but they didn’t incorporate green threads and their GC scheme is not performant for intense sharing and if you're not going to do intense sharing then the reference capabilities do not need to be as complex and I posit the GC scheme can be made radically more performant with a paradigm-shift. I wrote more details about this in the WD-40 thread #35. P.S. Yet another example of how design-by-committee creates a clusterfuck, setting up Unicode character shortcuts for ellipsis, right and left quote marks in Kubuntu is byzantine, although https://askubuntu.com/questions/1095339/how-can-i-input-unicode-characters-in-kate-and-konsole-on-kubuntu-18-04 Maybe eventually I will find the compose key combinations for all the Unicode characters I want: https://en.wikipedia.org/wiki/Compose_key#cite_note-xorg-12
|
“Uncle” Bob Martin points out in the “The Future of Programming” that the rate of increase of programmers is growing so fast that more than half of the programmers have less than 5 years experience and are young. Apparently the younger the programmers, the more heavily tilted towards males the programmer demographic is. https://youtu.be/ecIWPzGEbFc?t=3055 The implication is that PLs and frameworks are becoming less disciplined because the programmer demographic is becoming less disciplined (young age, low-level of experience, high testosterone, more energy than wisdom, etc). |
Despite @shelby3's accurate understanding of my technical points, which I appreciate, he's misunderstood my non-technical points almost without fail (e.g. mistaking the logical thoroughness of breaking down a situation into cases as an implicit accusation of the negative parts of each case). I do want to clarify that I am an extremely strong proponent of freedom of expression, just not of having ideology litmus tests backed up by strong rhetoric to try to drive away people with valuable technical skills. @keean - I don't know if you've programmed in Rust, but along with your comment about Rust being a most-loved language, it's useful to know why Rust is most-loved. It's not just because they've learned from history in a number of areas (e.g. crates, docs, community) and created either a best-in-class or a refreshingly-nice-alternative (for those people who want to use Rust). It also solves a problem that many systems-level programmers have, and for which there were zero good solutions, which is how to use mutability safely. Not every new language has to allow the same thing. Immutability is another approach, though if you think the borrow-checker is annoying, try putting someone up against either the borrow-checker or the entire field of pure FP ("so, you see, just use State, except no not really, use IO instead...but anyway, monads don't commute, so we need monad transformers (uh, actually, a lot of them), except that final tagless is a better way to go, except..."), the borrow-checker both admits much higher performance without insane compiler wizardry, and is a lot easier to swallow. (Admittedly it solves many fewer problems, but for that problem it's absolutely brilliant.) I've done a lot of programming in C++ over the years. Although I occasionally get frustrated with Rust not allowing something that is "obviously" safe, it is VASTLY outweighed by the number of times that it stops me from doing something obviously "safe", meaning actually not safe at all, and I didn't think it through carefully enough. It's almost as big an advantage for me as having strong types instead of none. My point in writing this is not to say that you have to bite off the whole borrow checker thing. My point is that Rust has that covered, and it's a very compelling feature, and if you go head-to-head with it, you have to either come up with something incredible, or you will lose. (That goes for multithreading, too...it's not enough to be 30% better at multithreading if Rust can beat you by 2x on single threads.) If you don't need to go head-to-head, though, because you're targeting a different area (e.g. not the-very-fastest-speed), then the design constraints are a bit less acute. Competing with Go is vastly easier than competing with Rust on a technical level. (Sociologically it may be harder...I'm not sure.) All this makes me wonder if you've read about Unison, specifically its abstraction construct which it calls abilities. |
@Ichoran I have programmed in Rust, and I have published the iterator chapter from Stepanov's "Elements of Programming" translated to rust as best I can, here on GitHub. Rust has some nice ideas, but fails in the execution for me. The borrow checker is ad-hoc, and has no systematic design, which means it misses obviously safe cases, and the work arounds add complexity to the language. The type system also seems thrown together with no use of well known concepts from the functional world that solve the problems (like universal and existential quantification). Again this results in corner cases with undefined behaviours, or unsoundness where the type system and the language semantics don't match up. I agree that the safe concurrency is nice, but it is frustrating that it does not allow common use cases like two write pointers to non-overlapping sub-regions of the same region. I would like to see algorithms like quick-sort accepted as safe. I am reasonably sure that there are some identities missing from rusts analysis. If I was going to take on Rust I would want to have solutions to the above problems before doing so. I have a feeling all of these problems are solvable, but not without breaking changes, so the question is, will Rust make them, are they even looking at this? How different from Rust would a language designed around getting the above type-theory correct would such a language look. Again, for me Go's lack of generics makes it a non-starter. It's like going back to 'C' from 'C++', at first you appreciate the simplicity, and straightforwardness, but by the time you write your third linked list implementation for a different type, you are over it. They are adding generics to Go, but it's going to have added complexity because it's not in the original design, and they have to work around certain things. For me lack of interfaces for operators adds needless complexity to generics. The thing is that neither of these languages are really a "target". They all tackle different aspects of the same problem space. The language I am looking at could be used for some problems you would use Go for but not all, and some problems you would use Rust for but not all. I guess I the end I want to design the language I want, that fixes the issues I have with all the other languages I have programmed in. Designing a language is a big task, so I keep hoping someone else will do it for me. When I try a new language, or a new language is created, I get excited that this might be the one, so I start trying to implement solutions to common problems from my experience. I have written software in Assembly, C, C++, Logo, Java, Pascal, Haskell, Ada, Perl, Python, JavaScript, TypeScript, Prolog, Go, Rust, and maybe some I have forgotten. All of these have some parts I like , and some I dislike. The work in Stepanov's "Elements of Programming" is the best treatment of generics I have come across, but I find the use of C and pointers problematic. Ada does well without pointers and the generics are better than C++ templates, but it has some difficult restrictions that make efficient programs hard to write, like the inability to return a writable reference to an array cell, even if you are sure the array is still in scope. |
@Ichoran and @keean I have continued the tangential discussion about Rust in the WD-40 issues thread #35 where it belongs. I rebutted or let’s say responded to @Ichoran in the aforelinked reply. EDIT: I also replied to @keean’s latest comment at the aforelinked. |
Thanks, @sighoya |
@sighoya sorry deleted by accident. Asked to be restored, now waiting... |
In case you haven’t already noticed, I created a new thread interim while we are waiting for Github to hopefully restore that thread. I sure hope it isn’t lost. There is a few years of valuable discussion in that thread.
Are you sure his ongoing problem was mentions from other users because you and I had stopped mentioning him but he came back 3 hours after our cluster of mentions apologizing to him, and said he was still being emailed. Did Github auto-subscribe him to the thread? He said he tried to unsubscribe from the thread. Here is what he wrote last in the accidentally deleted thread #35:
|
The big break in computer languages
|
Is less verbosity the only main benefit of typeclasses over just inputting a set of functions?
Typeclasses can do where
bar
is a member ofFunction
:Without typeclasses we could do:
I understand @keean proposed other functionality for the
where
clause, but as for the main functionality of providing pluggable (i.e. dependency injection) interfaces, what is the big benefit that justifies creating a new language?The text was updated successfully, but these errors were encountered: