« first day (212 days earlier)      last day (2187 days later) » 

10:33 AM
@Zanna Well, it's a suggestion. I'm not sure I can really recommend a language I have so little actual working knowledge of. ...but perhaps APT terminology is rubbing off on me.
 
hahaha
 
There is a social context underlying my interest in statically typed compiled languages. Dynamically typed interpreted languages have become enormously popular. Part of the popularity of Python and Ruby is in doing things people used to do (and still sometimes do!) with Perl, or PHP, or Tcl, or with shells. But they have made huge inroads into areas where statically typed compiled languages were traditionally used, too. Python, in particular, is huge these days.
Traditionally, in statically typed languages, you would declare all your variables before first use (still most statically typed languages require this), and you would specify the full static type of each variable when doing so (which newer languages, and newer dialects of older languages like C++, are increasingly no longer requiring).
There's a lot of code that gets written to satisfy the demands of statically typed languages, even though there's no fundamental reason why a language needs to impose that just because it's statically typed, because compilers should be able to infer most type information, because it is statically typed. So I am very interested in statically typed languages that lessen or remove that burden.
It's that burden that I see as a major driver toward dynamically typed languages for projects where a statically typed language might otherwise be used. Suppose, for example, that you had a list of positive integers representing coin values (and that they don't necessarily have any particular arithmetic relationship to one another) and you wanted to write a program that tells you, given a total value, how many distinct ways there are to make exact change for that value.
This is often called the "coin change problem." There are a few approaches to it. One approach is to recursively solve subproblems.
For example, if the target sum is 100, and the first coin is worth 7, then the number of ways to make change for that are the number of ways to make change for 100 without the first coin (use none of the first coin), plus the number of ways to make change for 93 without the first coin (use one of the first coin), plus the number of ways to make change for 86 without the first one (use two of the first coin), and so forth.
This recursive solution is very slow, but you can make it faster by recording the solutions to every subproblem solved, so that its result can be looked up instead of solved again during the course of solving the same problem. The data structure that holds the subproblems' solutions will map from (index, subtotal) to the number of ways there are to make change for subtotal using only coins starting from the indexth coin.
It's common to use a hash table to map from pairs of integers to integers. To declare this memo table in C++, it almost works to write:
unordered_map<tuple<int, int>, int> memo;
I say "almost" because tuple<int, int> isn't actually hashable, so you'll have to write a hash function for it, or make your own type that does it. Similarly, in Java, you would have to make your own type that does it. (Of course, you might decide to solve the coin change problem using a different approach instead.) Although this is one source of complexity, it's not really the one I'm focused on.
This has worked for years in C#... and it still involves a complicated declaration:
var memo = new Dictionary<Tuple<int, int>, int>();
The more traditional way to write that in C# was:
Dictionary<Tuple<int, int>, int> memo = new Dictionary<Tuple<int, int>, int>();
And there are still situations in C# where you have to write code like that.
Java does't have a tuple type, but suppose you've made your own Subproblem type that represents an (index, subtotal) pair. Then you would write:
Map<Subproblem, Integer> memo = new HashMap<>();
In newer versions of C#, there is a ValueTuple type with language support, so that you can write expressions like (2, 3), and you can write declarations like this, instead of that (this uses ValueTuples rather than Tuples but that's probably actually better in this case anyway):
var memo = new Dictionary<(int, int), int>();
All of this involves the programmer writing code to tell the compiler what type of thing memo is. Even though some of these approaches actually do use forms of type deduction--var in C# deduces the type from the expression on the right of the = sign that gives memo its initial value, and in the Java example new HashMap<>() is short for new HashMap<Subproblem, Integer>()--nonetheless they require you to specify the type.
In contrast, in Python or Ruby (in this case the code of either language is the same) you would just write:
memo = {}
Then memo is a dict in Python or a Hash in Ruby. It can be used to map anything (well, anything hashable) to anything. You get no enforcement of correctness from the interpreter to stop you from accidentally using something that isn't a pair of integers as a key or that isn't an integer as the value.
And because {} can be used to store anything, the types of every object used to store or look up a value in memo have to be checked at runtime for each operation and there are no real opportunities for optimization (though that's actually also the case in Java, due to the way generics in Java work).
People are using dynamically typed interpreted languages for a lot of things because you don't have to write as much code and the code you do write is easier to read. (Even with Perl, which is notoriously hard to read if the author doesn't really exercise self-discipline in writing it, there is still at least less code to read.)
But there's nothing fundamental about statically typed compiled languages that makes them cumbersome in this way; you should be able to write things like memo = {}, and optionally be permitted to apply a type annotation that ensures a particular type.
Even if you don't apply the type annotation, memo should still be a Dictionary<Tuple<int, int>, int>> (or whatever), because the compiler should be able to infer its type from the way you actually use it. If you use it with keys that are of different types or values that are of different types, then the compiler should complain.
There are some languages that let you do this, and there are others that approach it. Kotlin doesn't really get you that far, but it gets you closer than most popular languages, and Kotlin code is far less verbose than Java code. Boo and Nemerle, both of which target the .NET Framework and Mono, actually let you do this, but (unfortunately!) those languages are obscure.
Boo was supported for writing games in Unity, but was dropped. Not enough people used it to make it worthwhlie for the company to support it. Now it's hard to install the tools for Boo, and I don't think it's still developed or targets the latest versions of the framework. Nemerle is still active, but not many people use it. I'd be reluctant to recommend (or even, uh... suggest) either as someone's first general purpose programming language.
There are functional languages, like F#, that are statically typed and that get you close to this goal, though not all the way there. One of the things about F# that is arguably quite nice is that you write programs in a linear fashion, with type inference being conducted rightward in expressions and downward in your program. But this means the type of an expression is not inferred from its later use. (But compared to most languages, F# infers just about everything, most of the time. :)
There are arguments for learning a functional language as a first general-purpose programming language. MIT used to use Scheme in their intro course (but now they use Python). Functional languages are like math in the one big way math is more intuitive than programming. But there's no reason powerful type inference shouldn't be in languages oriented toward procedural programming or OOP, which remain the most popular kinds of languages.
 
12:34 PM
When C++ got auto in C++11 (in its current meaning--auto had a different, obscure meaning in earlier standard dialects of C++, and was rarely used), there was controversy over when it ought to be used.
In its simplest and most common use case, auto lets you declare variables whose types are inferred from their initializers. So, for example, you can write auto x = 3; instead of int x = 3. Now auto is widely accepted in the C++ community; many C++ programmers use it almost all of the time. Part of the reason to use it is that it helps avoid unintended type conversions than can occur because C++ is not as strongly typed as some other languages (though it is more strongly typed than C).
The thing is, type deduction is done by the compiler of just about any compiled statically typed language. When you write an expression like x + y, its type is deduced from the types of x and y (and from however the meaning of + is ascertained, which varies by language--and, of course, not all languages have an infix + operator). This is the clearest explanation I've seen for why it's often appropriate to use auto in C++.
Now, there is an argument to be mad that the extremely powerful kind of type deduction that I am advocating--where the type of a variable is determined by how it is later used, if its first use does not clarify what its type should be (and the programmer does not supply a type annotation)--nonetheless goes too far. After all, it involves looking at later code to determine the behavior of earlier code. But... that, too, is something that people seem to have no problem with in other contexts.
In some languages, like C and C++, but also others like F#, I cannot call a function that has not been yet declared. A declaration must precede the first use of the function. But in most languages, nowadays, that is not required. I would consider Java to be a good example of this because, in Java, there is a strong ethos that it is good to be explicit about what you are doing and about the types of all variables one introduces.
This is why Java has nothing like the var keyword of C# or the auto keyword of C++ (though it does have diamond inference)‌​. Java is a very verbose language, in general. But in Java, you do not have to define a class or method before it is used (like you do in F#), nor even declare it before it is used (like you do in C and C++); in fact, you really can't declare those things, you just define them somewhere.
And like C++, Java lets you overload methods. You might write f(x + y), where multiple functions called f that take one argument are defined, even below where that expression is evaluated.
Not only does the compiler infer the type of x + y, it uses that to infer what f to call... and it uses the return type of that f to determine the type of the whole expression, so you can write w + f(x + y).
 
1:21 PM
I think the reasons dynamic interpreted languages--where the meaning of each operation is determined at runtime, usually each time it is performed--are extremely popular these days is primarily because the statically typed compiled languages that enjoy wide adoption are needlessly verbose and cumbersome, and only secondarily because of benefits that are truly unique to dynamic languages. I could be wrong about this, and you shouldn't accept it uncritically.
There are also aspects of these issues I haven't talked about. For example, there are statically typed compiled languages that undertake considerable dynamic behavior, through dynamic dispatch, which occurs when virtual functions are called. (This is nearly ubiquitous in Java.)
 
1:32 PM
However, if I am right about why dynamic languages are so popular, then I think the implications are considerable. This is not just a cerebral exercise in comparing programming languages, because as long as dynamic languages are slower, i.e., as long as they require more processing to do something that could be done with less processing, the practical consequences are hard to escape.
There's a widespread attitude these days that it doesn't matter if code is slow, because computers are fast: even slow code runs fast! There is some truth to this, and it's true that it is impractical and unreasonable to try to make everything run as fast as possible all the time. There are also plenty of things where there's no point in optimizing them because they already account for such a tiny percentage of processing.
For example, if you write a program in Python that use NumPy, most of the actual processing might be done by the NumPy library itself, which is implemented in C, even if most or all of your own code that uses it is written in Python. But not everything reduces to "oh it's fine, the computationally intensive part is written in a faster language anyway." Something has to actually be written in a faster language for that to be true.
This is not really about speed. Not usually. To word it in an overbearing and sort of silly but accurate way: it's about the total computational resources of humanity. We have lots of fast computers. If we write code that does a lot of processing, we're still not likely to run out of them. The cloud is huge and growing. But the electrical power used by those computers still has to come from somewhere.
(Also the materials used to make the computers, the energy used to manufacture and transport them, and used to manufacture their parts and transport them, and so forth.)
 
 
1 hour later…
2:55 PM
I see some people write ${var} for all their vars even if they aren't doing anything to them. I've always wondered what the purpose of that was
 
Well there are situations where you cannot write $varbut can write ${var}, like "${var}text". Aside from that sort of thing, a possible argument for writing ${var} instead of $var is that if it becomes like that in the future, then you're not likely to accidentally fail to add the braces. Another possible argument for writing them is that it makes it more clear that it is parameter expansion, but I don't think I really agree with that reasoning.
But Ruby has something like that in its syntax for string interpolation, where the braces are sometimes optional but sometimes required, and I do always put in the braces (though partly just because it is widely accepted practice to do so).
...Should this be moved to the island? Also, are we still moving stuff from here to the island like we used to (after creating the island). I was less active in here for a while and I noticed that stuff didn't seem to be getting moved. I think there was someone who asked a technical question in here not related to the topic of the room, and that conversation wasn't subsequently moved. I considered moving it and a few other messages, but I wasn't sure if I should. I can still do so, of course.
I might be the main reason the island is needed, I guess... :)
I am asking about the island in here, but assuming we're still using it for its original purpose and you want me to move stuff there, I can move this there too.
 
3:25 PM
@EliahKagan yes I didn't move those messages because I didn't want to confuse that person. I didn't feel like explaining the purpose of the island to them, and during that period, it was extremely rare than anyone responded to me when I mentioned any moderation issue. So there was no reason to keep the room clear in order to help moderation issues get attended to, since they were not getting attended to here anyway :(
however these messages that are Islandy could be moved because a) nobody involved will be confused by their being moved and b) this room is apparently being used for moderation again :)
 
4:04 PM
Although Ruby is not fast (yet?), I hope you do not interpret what I am saying as discouragement from learning it. I think you had mentioned that you had tried a brief introduction to Ruby a while ago, but for some reason I cannot find that chat message. Have you done anything with it more recently?
(I'll be back later.)
Understood. I'm about to go afk and I'll likely be afk for most of the day, but I can try and move them when I get back. (I don't want to do it hastily, because I don't want to accidentally move messages that should not be moved, and because that way I'll have time go to far as far back as the point at which messages had last been moved.)
 
ok :) no worries if you don't feel like moving them... I am not going to move them because I'm not sure about which ones should be moved so that everything still makes sense
 
I should be able to do it. I expect I will feel up to the task if figuring that out. :)
 
:)
 

« first day (212 days earlier)      last day (2187 days later) »