2016-12-11

mindstalk: (Default)
So I've learned that gcc/g++ do tail call optimization with the -O2 option; supposedly MS Visual Studio and clang do it when they can as well. I have tested this:

this got long )
mindstalk: (Default)
At my last onsite interview I got asked -- out of curiosity, not as interview question -- what was so great about dynamically typed languages. I struggled to explain -- everyone knows why they're cool, right? Code is fast and compact to write! It is known!

But I've been thinking about the question some more. Right now I'm thinking there's one thing they're genuinely better at that doesn't come up that often; for the rest, it's more a historical accident of feature packaging, i.e. what else has traditionally come along with dynamic typing that made coding convenient.

The one thing: dealing with some variable length list of arbitrary values that you deal with at run time. Stuff like printf(), or message-passing into a closure-based object. I think I mentioned building a closure object in ocaml, and you can do it, but you need a sum type for various method inputs, and another for output, and it just seems like more work. Yeah, you get type safety for the work, but it's still more work. Likewise C has long had an ability to make things like printf(), but it feels clunky.

Also, based on language features, it seems likely that Lisp-style macros work better with dynamic typing, but I can't defend the claim. eval() seems to go with dynamic typing too, not that it's used that much IME.

The other stuff that's tended to come with dynamic typing:

* direct running of code, without a manual compile step. So faster development.
* (Lisp and Python, but not Perl or Ruby AFAIK): a REPL so you don't have to even write code into a file to run it, but can play at a prompt.
* easily making product types (tuples, lists of arbitrary types.) In C you have to declare and define a struct.
* garbage collection or at least reference counting, so little need to worry about memory management. Corollary: if you stick with small or at least short-lived "scripts", then resources like file descriptors or file handles don't have to be worried about much either; that's a domain thing rather than a language thing.
* And what might be the biggest one, a convenient environment:

In C you need to define a main function and include at least one header (like stdio.h) to do anything. Java's entry point is even more verbose. By contrast, a one line print statement is a valid scripting language or Lisp program. Put another way, in C++ terms, simply starting Perl gets you roughly the equivalent of


#include cstdio
#include string
#include regex
#include deque
#include unordered_map
#include unistd
#include sys/socket.h
#include cstdlib

...and probably more. (I left out the angle brackets because Dreamwidth is annoying.)


plus any statements are assumed to be contents of main() and thus executed. Python makes you import a few of the above as modules, though adds , bigints, and complex numbers.

Now, none of this depends on dynamic typing! ocaml and ghci provide REPLs and ocaml can directly run source files. Type inference and compact notation makes creating typed tuples on the fly trivial (on the fly coding, at least; not at runtime). Java's GC feels like half the reason programmers originally ooh-ed over it. And while Perl's default environment is unmatched AFAIK, having strings and some sort of container types and IO (more than C/C++) without import or use statements is common to Java and the ML-ish languages.

But if your experience of languages is something like C++, Java, and Perl/Python, as was not uncommon, then there's a clear bias in code convenience and compactness. And even with the ML-ish languages, with type inference and REPL, there's still nothing that matches Perl for simply doing useful system stuff right away without imports. I see no reason one couldn't exist, it just doesn't. So it's easy to associate dynamic typing with "lets me get stuff done quickly and concisely".
mindstalk: (Default)
One thing easy to miss about Python is how it can easily print anything, including lists of dictionaries of lists of objects.  C++, not so much.  So I wrote a simple template function to print a vector of printable types, and then one for deques.

template<class T>
void pr_vector(const vector <T> &v) {
    for (auto i : v)
        cout << i;
    cout << "\n";
}
template<class T>
void pr_deque(const deque <T> &v) {
    for (auto i : v)
        cout << i;
    cout << "\n";
}

Well, lots of duplication there.  I tried templating on the container type too, template <class C, class T>, but the resulting C <T> didn't work; it probably should with some syntax, but I don't know what, yet.

But I figured I'd try auto:

void pr_cont(const auto &v) {
    for (auto i : v)
        cout << i;
    cout << "\n";
}

...that subsumes both templates.  And lots of others.  vector, deque, list...  Of course, the values themselves have to be printable, it can't handle a vector<pair<int, string>> because there's no printing on pairs.  But still, for C, this is amazing!

Profile

mindstalk: (Default)
mindstalk

May 2025

S M T W T F S
    123
45678910
11 121314151617
1819202122 23 24
25262728293031

Most Popular Tags

Expand Cut Tags

No cut tags

Style Credit

Page generated 2025-05-29 15:20
Powered by Dreamwidth Studios