Welcome, Guest. Please login or register.
March 28, 2024, 05:42:00 pm

ballp.it is the community forum for The F Plus.

You're only seeing part of the forum conversation. To see more, register for an account. This will give you read-only access to nearly all the forums.

Topic: Thread.setTitle("Programmers Anonymous");  (Read 60780 times)

Nifty Nif

  • Big Dumb Slimy Monster
  • Paid
  • powerful and can be dangreous
  • 809
  • 51
If we start talking about Rust in here I'm going to start having a lot of opinions about Rust so I'm going to resist the urge to do that.  (I worked on it as a paid contributor for a brief internship.)

I'm also going to resist the urge to go deep about functional programming.  I have a lot of opinions about that too.  Javascript is beautiful when written functionally, though, and I think NodeJS really takes advantage of that.  Promise yourself to stay out of Callback Hell!  I also think Haskell is gorgeous and I'd love to get into it.

Here's a personal thing: I'm sick of Java haters.  Call me bias [sic], but it's an immensely powerful language that has given rise to some incredible design patterns, and if you don't like reflection you can fuck right off.  I like reflection a lot.  Sure, it's dangerous in the wrong hands, but I can unit test literally any codebase I want with the right libraries.  Haters gonna hate, I'll just be over here with my 100% test coverage and then we'll see who thinks what of Java.

Zekka

  • I AM IN INTO MATHEMATICAL CALCULATIONS AND MANY METHODS USED IN THE STOCK MARKET
  • Paid
    • 872
    • 54
I think Java's a little bit too verbose for its own good, but I think it's very faithful to the "don't give people features that they will abuse" credo. I think that the default way of doing a lot of stuff in Java is usually wrong though. Example: there's not a good builtin pattern in Java to derive an extra suite of operations for an object that already supports a smaller one. (Rust has traits, Haskell has typeclasses, Scala has implicits)

I softened on this a lot though after spending a lot of time translating Haskell code to Java. Example with the trait pattern: you can simulate the Haskell, Rust, and Scala approaches by foregoing code that looks like this:

public interface List<T> {
  public T get(int i);
  public void set(int i, T t);
}

public interface Iterable<T> {
  public Iterator<T> iterator();
}

// any List must opt into being Iterable by implementing IterableList instead of implementing List
// if a List author was not aware of IterableList, his List will not support the Iterable operations
public interface IterableList<T> implements List<T>, Iterable<T> {
  default Iterator<T> iterator() {
    // builds a default Iterator that uses the List<T> methods
  }
}

and writing your java code like this instead:

public interface ListOperations<This, T> {
  public T get(This this, int i);
  public void set(This this, int i, T t);
}

public interface IterableOperations<This, T> {
  public Iterator<T> iterator(This this);
}

// you can instantiate this for any ListOperations -- the ListOperations does not have to opt in
public final class ListIterableOperations implements IterableOperations<This, T> {
  private final ListOperations<This, T> asList;

  public ListIterableOperations(ListOperations<This, T> asList) {
    this.asList = asList;
  }

  public Iterator<T> iterator(This this_) {
    // build an Iterator<T> using this.asList
  }
}

This is actually exactly the pattern Haskell uses to compile its equivalent of interfaces. (Haskell interfaces have a feature where you can automatically deduce that an implementation like ListIterableOperations applies to any List) After I saw what Scala did to this pattern with implicits, I actually kinda prefer this take -- it's way less abusable. (Haskell's feature is also quite abusable, but the community is way more aggressive about avoiding the usages of implicits that make code harder to understand.)

I think Java is a pretty good language for super verbosely specifying patterns involving vtables and GC'ed records-referencing-records. I just think a lot of people default to using its features in ways that are not super sound (most patterns involving subclassing non-abstract classes) or which discourage code reuse. (interfaces for the objects that contain the data)
A Whirring Bone-White Gleech
« Last Edit: July 22, 2016, 05:53:44 pm by Zekka »

Nifty Nif

  • Big Dumb Slimy Monster
  • Paid
  • powerful and can be dangreous
  • 809
  • 51
I think Java's a little bit too verbose for its own good, but I think it's very faithful to the "don't give people features that they will abuse" credo. I think that the default way of doing a lot of stuff in Java is usually wrong though. Example: there's not a good builtin pattern in Java to derive an extra suite of operations for an object that already supports a smaller one. (Rust has traits, Haskell has typeclasses, Scala has implicits)

I softened on this a lot though after spending a lot of time translating Haskell code to Java. Example with the trait pattern: you can simulate the Haskell, Rust, and Scala approaches by foregoing code that looks like this:

public interface List<T> {
  public T get(int i);
  public void set(int i, T t);
}

public interface Iterable<T> {
  public Iterator<T> iterator();
}

// any List must opt into being Iterable by implementing IterableList instead of implementing List
// if a List author was not aware of IterableList, his List will not support the Iterable operations
public interface IterableList<T> implements List<T>, Iterable<T> {
  default Iterator<T> iterator() {
    // builds a default Iterator that uses the List<T> methods
  }
}

and writing your java code like this instead:

public interface ListOperations<This, T> {
  public T get(This this, int i);
  public void set(This this, int i, T t);
}

public interface IterableOperations<This, T> {
  public Iterator<T> iterator(This this);
}

// you can instantiate this for any ListOperations -- the ListOperations does not have to opt in
public final class ListIterableOperations implements IterableOperations<This, T> {
  private final ListOperations<This, T> asList;

  public ListIterableOperations(ListOperations<This, T> asList) {
    this.asList = asList;
  }

  public Iterator<T> iterator(This this_) {
    // build an Iterator<T> using this.asList
  }
}

This is actually exactly the pattern Haskell uses to compile its equivalent of interfaces. (Haskell interfaces have a feature where you can automatically deduce that an implementation like ListIterableOperations applies to any List) After I saw what Scala did to this pattern with implicits, I actually kinda prefer this take -- it's way less abusable. (Haskell's feature is also quite abusable, but the community is way more aggressive about avoiding the usages of implicits that make code harder to understand.)

I think Java is a pretty good language for super verbosely specifying patterns involving vtables and GC'ed records-referencing-records. I just think a lot of people default to using its features in ways that are not super sound (most patterns involving subclassing non-abstract classes) or which discourage code reuse. (interfaces for the objects that contain the data)
Zekka, July 22, 2016, 05:49:49 pm

Okay, sure, I get the verbosity thing.  But I... I actually like it.
Take your examples.  I actually think the first one is more readable than the second one.  This may come from me being an environment where I write and read Java all day long, or maybe you don't do much OO.  I'm also super used to working on a team, so if someone inherits your code base, practically speaking, they've got to be able to write to it.  In order to do that, they've got to read it first.  Java may be wordy, but it's really explicit about what it's doing, so it's really easy to pick up.

On the OO front, yeah, sorry, Java's type inheritance only goes down and sideways.  It is, to your point, faithful to its credo of giving people features that they will use well, so you get to interface stuff (sideways) and subclass stuff (down), but you don't get to do the inverse (going up, or having to opt-out of features).  Your second example does look very much like Rust or Haskell, for sure, and maybe that is why it made something in my brain itch a little bit.  It feels like something I dislike about Rust, which is its inherent elitism.

Oh boy, here I go.  Seeing myself out now before I go on a tangent.  You're not an elitist, Zekka, don't worry.  I just have a lot of feelings.

Zekka

  • I AM IN INTO MATHEMATICAL CALCULATIONS AND MANY METHODS USED IN THE STOCK MARKET
  • Paid
    • 872
    • 54
Minor note on verbosity thing -- I think you could cut Java verbosity a lot just by shortening keywords, implicitly making things private, making inner class syntax much shorter, and providing literals for lists and maps.

I guess what I'm arguing about with Java is something similar to what I usually argue to Haskell programmers. Haskell has a very idealized worldview where your code only asks for as much power as it needs -- as a result, you have multiple lifts that give your code varying amounts of power. In roughly ascending order of power (although there's no strict ordering). These are the functions in the standard library that represent various ways to ask for "pretty please, give me {mutation support | access to the outside world | coroutines | error handling | suboxone}":

(<$>) :: (a -> b) -> (f a -> f b)
(<*>) :: f (a -> b) -> (f a -> f b)
(=<<) :: (a -> f b) -> (f a -> f b)
lift :: f a -> (g f) a
-- this one doesn't fit the mold of the others but I'm throwing in because it breaks EVERYTHING
runST :: (forall s. ST s a) -> a

These all correspond to the same *meaning*, which is something roughly like:
liftPlease :: some kind of a -> some other kind of a

Since Haskell has this worldview where you only want to use the one that has exactly as much power as you need, you have to remember four or five ways to write the same thing. (I was kind enough to spare you the Traversable and Foldable operations, which give you three or four more ways to write it.) You can kinda solve the problem in Haskell by writing everything as an (a -> (g f) b): then you only care about (=<<) and never have to use any of the other operations. But that's opting out of Haskell's worldview.

I think Java-style OOP starts with very weak primitives which often are not that powerful by themselves, and you're kinda right -- if you want to force Java to give you additional powers, you have to get a little crude and ugly, because when you do that you're opting out of Java's world-view. I think Java's builtins have the same appeal as Haskell primitives -- writing Java the way I learned to write it is kind of like bootstrapping your favorite language's data model in C, except you get a garbage collector too. You can get exactly the powers you want and no extra ones. Your abstractions are pretty close to the machine and there's no magic going on under the covers -- in exchange, all you get are vtables and your base inheritance feature is kinda weaksauce, but guaranteed non-evil.

If you don't want bootstrapping to be part of your problem, though, Java's inheritance primitives are weak and punish you for writing all the code that means the same thing the same way. (it's probably not just the inheritance primitives -- I think a lot of design patterns are reactions to similar problems that happen if you use Java naively) Its builtins are not that flexible, because its worldview is that its builtin inheritance is all you need. Sometimes you really need the trait-like formulation, and other times you can totally get away without it. I found Java really frustrating until I got used to thinking about it like that, and then I only found it mildly frustrating.

My alternative probably would have been to write all my code in a language whose default data model looks like one of the ones I bootstrap, like Prolog or Haskell. But I actually did used to write almost everything in Prolog and Haskell and I don't think they're as suitable for the general case as your generic typed imperative language. (I felt like Haskell made a lot of my problems harder, not easier, even after I was very comfortable with how it was meant to work.)
« Last Edit: July 22, 2016, 07:58:36 pm by Zekka »

Zekka

  • I AM IN INTO MATHEMATICAL CALCULATIONS AND MANY METHODS USED IN THE STOCK MARKET
  • Paid
    • 872
    • 54
I think I made things confusing. Quick attempted summary:

Basic Haskell worldview: you need to ask for more power if you want to get access to resources. There are a lot of fiddly, specific ways to do this. The built-in model is probably inadequate. This is weird and hacky, and you need to remember lots of different ways to do it.

Basic Java worldview: our builtin tools are good enough. There are not tools to ask Java to do a lot of things you likely want to ask it to do. There are fiddly, specific ways to do it anyway. This gets weird and hacky, and you need to remember lots of different ways to do it.

Conclusion: in the domain of access to resources Haskell is intentionally annoying for dogma reasons. IIn the domain of data modeling, Java is accidentally annoying for lack-of-foresight reasons. Java's builtin annoying tools are operationally easy to explain. (pretty fundamental to how the computer works) Haskell's builtin annoying tools are operationally hard to explain. (a significant layer above how the machine works) Opting out in Java means being more explicit about what your code does, making your code superficially more complex. Opting out in Haskell means being less explicit about what your code does, making it superficially simpler.

Gyro

  • touched fuzzy, got dizzy
  • Paid
  • 830
  • 55
If we start talking about Rust in here I'm going to start having a lot of opinions about Rust so I'm going to resist the urge to do that.  (I worked on it as a paid contributor for a brief internship.)
Nifty Nif, July 22, 2016, 05:26:06 pm
I actually want to know the Rust opinions. I'm using it and working around the borrow checker is kind-of a bitch, especially when you need to work with explicit lifetimes, but I enjoy a lot about the language so far  - pretty great support for metaprogramming, the lightweight and non-restrictive nature of traits, binary literals, operator overloading exists, and, as a bonus, I like the syntax.

Here's a personal thing: I'm sick of Java haters.  Call me bias [sic], but it's an immensely powerful language that has given rise to some incredible design patterns, and if you don't like reflection you can fuck right off.  I like reflection a lot.  Sure, it's dangerous in the wrong hands, but I can unit test literally any codebase I want with the right libraries.  Haters gonna hate, I'll just be over here with my 100% test coverage and then we'll see who thinks what of Java.
Nifty Nif, July 22, 2016, 05:26:06 pm
I agree with you a lot, actually. Java is a pretty good language - especially modern Java, with annotations and typechecked generics.
Nifty Nif

A Whirring Bone-White Gleech

  • fact-lord
  • Paid
  • I was in first place, you whore!
  • 720
  • 155
I'm one of the people who really, completely detests Java (and, for context, loves python and C#).  I agree that C++ was sort of a mess, but Java removed way too much of it, and left us with an under-expressive, awkward language.  I think the rich panoply of design patterns in Java is sort of an indictment of the language, because I kind of feel like a common design pattern is a thing that your language probably should have automated (and probably should automate in its next release).

Python has a lot of the features that Java won't give me because I might abuse them (like multiple inheritance and operator-overloads).  And python's duck-typing frees me from ever having to specify an interface.  And that makes me more productive, and the sky hasn't come crashing to the earth.  (Then again, I am coding in an academic context, so...)

C# has added (and added back) a lot of the features that Java lacks, and is a vastly better language for it.  C#'s support for delegates and events removes the need for several annoying Java design patterns, and I think that C# Properties are just the greatest fucking things.  (Properties are a feature that I really wish Python would import.)

I really regret all the inane politics around Mono; I'd work in C# so much more if I could. :(

ETA: I feel like I'm coming off as a real bitch in this thread :(

ETA2: I'd also be really interested in hearing opinions about Rust.
« Last Edit: July 23, 2016, 02:25:29 pm by Der Trommelngleech »

Gyro

  • touched fuzzy, got dizzy
  • Paid
  • 830
  • 55
Python has a lot of the features that Java won't give me because I might abuse them (like multiple inheritance and operator-overloads).  And python's duck-typing frees me from ever having to specify an interface.  And that makes me more productive, and the sky hasn't come crashing to the earth.  (Then again, I am coding in an academic context, so...)

C# has added (and added back) a lot of the features that Java lacks, and is a vastly better language for it.  C#'s support for delegates and events removes the need for several annoying Java design patterns, and I think that C# Properties are just the greatest fucking things.  (Properties are a feature that I really wish Python would import.)

I really regret all the inane politics around Mono; I'd work in C# so much more if I could. :(
Der Trommelngleech, July 23, 2016, 02:21:12 pm

I agree with you about C# and Python - they're fucking fantastic, both of them, and I'd choose them over Java on most days. It's just that I don't think Java's problems sink it or make it infuriating. Don't try to multithread anything in Java, though, holy shit (Don't do that in Python either, the GIL won't let you).

I don't know, I guess I just like all of the languages that aren't PHP or Visual Basic.

Nifty Nif

  • Big Dumb Slimy Monster
  • Paid
  • powerful and can be dangreous
  • 809
  • 51
If we start talking about Rust in here I'm going to start having a lot of opinions about Rust so I'm going to resist the urge to do that.  (I worked on it as a paid contributor for a brief internship.)
Nifty Nif, July 22, 2016, 05:26:06 pm
I actually want to know the Rust opinions. I'm using it and working around the borrow checker is kind-of a bitch, especially when you need to work with explicit lifetimes, but I enjoy a lot about the language so far  - pretty great support for metaprogramming, the lightweight and non-restrictive nature of traits, binary literals, operator overloading exists, and, as a bonus, I like the syntax.

Here's a personal thing: I'm sick of Java haters.  Call me bias [sic], but it's an immensely powerful language that has given rise to some incredible design patterns, and if you don't like reflection you can fuck right off.  I like reflection a lot.  Sure, it's dangerous in the wrong hands, but I can unit test literally any codebase I want with the right libraries.  Haters gonna hate, I'll just be over here with my 100% test coverage and then we'll see who thinks what of Java.
Nifty Nif, July 22, 2016, 05:26:06 pm
I agree with you a lot, actually. Java is a pretty good language - especially modern Java, with annotations and typechecked generics.
Gyro, July 22, 2016, 08:18:59 pm

Annotations and typechecked generics are the bomb!  I think part of my affinity for Java comes from the fact that I have little experience with pre-Java 7 versions.  I love using Java 8 and I enjoy its support for functional paradigms.  It's becoming a more expansive language.  Generics are extremely useful also, and I know some critics think that they're overly powerful or not in step with Java's philosophy.  I disagree, as they're pretty fundamental to OO, IMHO.  I agree with @Zekka that you could implicitly make things private, though, that'd be nice.  Package-private is a bullshit designation that people don't really use that often.


Okay, Rust stuff.  I worked on Rust for a little while, and the feeling that I got while poring over loads of documentation and wrestling with the compiler for hours and hours was that the core design team had written a language with some incredibly robust features but didn't give a single fuck if it was unusable to everyone.

Sure, the documentation is arguably lengthy.  And yeah, maybe someone will give you the advice not to program in Rust if you don't understand the ins and outs of execution state, reference passing, etc.  As a developer who is fortunate enough to know a bit about a few impractical things, I think this is bullshit.  The situation as it stands is that Rust is a language with an insurmountably steep learning curve.  It only has real utility for kernel hackers, and it really does have great use for them (userspace concurrency, memory management with unsafe keywords, etc).  However, Mozilla is trying to pitch Rust as a C-killer, and Rust is too hard to use for that to ever be possible at this point in time.  They're trying to shoehorn Rust into Servo, their browser engine.  There was another engineer working on Servo at the same time as I was working on Rust, and I think she was using Rust to accomplish her task.  She had a lot of the same problems I did, as far as I could tell--the compiler doesn't cooperate as soon as you decide to pass a variable to another function, so you've got to decide whether to pass by value or reference, and god help you if you choose the wrong one.  The way around this is to use Rust's paradigms, but these are obscure and highly functional in nature and often inaccessible to the average developer. 

I did manage to write a gorgeous B-tree library (the task for my internship), but sadly, my laptop crashed on the last day of my internship and all of my work was lost right before I could commit, so all that's in the repo is the piss-poor OO one I tried to write, which never worked.  The only reason I was able to write a working implementation at all was because I was invited out to meet the core team at their research summit, and I had one of the head engineers write it with me.  Once it finally clicked, it was like magic.  I couldn't replicate it now--this was almost 3 years ago, and like I said, the work has been scattered to bits.  Good thing the feature I wrote was non-essential and will never exist anywhere for anyone.  Someone else has probably written it by now, or tried and failed again.

So the way to write Rust is to pretend you're writing Scala or Haskell or something, never an OO language, and just be as minimal as possible.  Once the borrow-checker starts arguing with you, throw your computer out the window or just write some nice Python instead.  Or maybe do something nice for yourself, like play video games or hang out with your friends.  Anything but program in Rust.  It's not a C-killer and it's not revolutionary.  It's just syntactic salt and syntactic sugar in the same jar.
A Whirring Bone-White Gleech nuffkins, of all people,

A Whirring Bone-White Gleech

  • fact-lord
  • Paid
  • I was in first place, you whore!
  • 720
  • 155
Python has a lot of the features that Java won't give me because I might abuse them (like multiple inheritance and operator-overloads).  And python's duck-typing frees me from ever having to specify an interface.  And that makes me more productive, and the sky hasn't come crashing to the earth.  (Then again, I am coding in an academic context, so...)

C# has added (and added back) a lot of the features that Java lacks, and is a vastly better language for it.  C#'s support for delegates and events removes the need for several annoying Java design patterns, and I think that C# Properties are just the greatest fucking things.  (Properties are a feature that I really wish Python would import.)

I really regret all the inane politics around Mono; I'd work in C# so much more if I could. :(
Der Trommelngleech, July 23, 2016, 02:21:12 pm

I agree with you about C# and Python - they're fucking fantastic, both of them, and I'd choose them over Java on most days. It's just that I don't think Java's problems sink it or make it infuriating. Don't try to multithread anything in Java, though, holy shit (Don't do that in Python either, the GIL won't let you).

I don't know, I guess I just like all of the languages that aren't PHP or Visual Basic.
Gyro, July 23, 2016, 02:54:36 pm

I'm of two minds.  On the one hand, maybe yeah, "terrible" is a bit too strong, and there are a lot of languages that are much, much worse; I can concede that Java is probably an improvement over C++ in a lot of ways.  On the other hand, I think C# is also just kind of strictly better than Java: the two languages are in substantially the same niche, and everything that's good about Java is good about C#, and a lot of the things that are bad about Java are not bad in C#.

The GIL is a weakness in python, but python threads are still useful sometimes.  Notably, the GIL is released when blocking I/O is happening, so that's a situation when python threads might still also be useful.

Gyro

  • touched fuzzy, got dizzy
  • Paid
  • 830
  • 55
Does anyone mind if I post projects / progress in this thread?

I've been working on a Minecraft clone in Rust. Just got the renderer to work last night.
Nifty Nif

Emperor Jack Chick

  • he/him
  • Ridiculist
  • Metal tyrant from hell
  • 3,193
  • 666
today i had a huge revelation about javascript when i opened up a function, looked at it, and exclaimed "what in the fuck are these inputs?" since the thing took two parameters and ofcourse there were no goddamned comments about what those inputs were supposed to be

and all of a sudden i understood why C style languages have their parameters initialized.


i literally ended up just trying a bunch of combinations until i discovered it was string/string and then PROMPTLY added a comment about it.


disclaimer: i am very bad at coding

immediate edit after: also last week i wrote some code that asserted to do some shit when true == false and i thought my developers were going to have a hernia :D (i needed it to fail 100% of the time)
Gyro

Emperor Jack Chick

  • he/him
  • Ridiculist
  • Metal tyrant from hell
  • 3,193
  • 666
the way that gitignore is designed is the most pointlessly ass-backwards possible
A Whirring Bone-White Gleech

McShrimpsky

  • The Kelly Clarkson of Pornhub.com
  • Paid
  • 21
  • 3
"what in the fuck are these inputs?"jack chick, July 28, 2016, 01:03:34 am
Yeah, I'm actually a fan of static typing (and Java in general) for this reason.  This is the one thing that bugged me when I had to go back to Java from Python, though.  It sure is nice to be able to declare functions that aren't wrapped in an arbitrary class, and static functions seem like a whole other can of worms that are generally frowned upon.

As for Javascript, I watched this talk about "The Good Parts" a while back.  It was pretty cool, but it made me realize that if you kept all The Good Parts of Javascript, while fixing all The Bad Parts of Javascript, the resulting language would literally be Python.

Zekka

  • I AM IN INTO MATHEMATICAL CALCULATIONS AND MANY METHODS USED IN THE STOCK MARKET
  • Paid
    • 872
    • 54
FWIW, there are a lot of languages that have static typing and not classes. "Languages like Java" vs "Languages like Python" is kind of a false choice.
Gyro