I can't think without a strong type system like that of C++ or Java. I just cannot comprehend code without strong typing.
For one, what am I supposed to do when my code is fed data of the wrong type?
Secondly, how am I supposed to know what kind of data types other code accepts?
These two simple questions make me get stuck. Python and JavaScript are great examples of languages I cannot think properly in. I'm too distracted by the lack of type safety.
I have a couple friends who are Python fanatics, and when I talk to them they say they never have any problems. No anxiety, worries, etc. but when I try to write in Python all that happens is anxiety prevents me from writing any code.
How does it work? I can understand small projects, but anything large seems like it would quickly get out of hand and fall into chaos. How do people write code at all in weakly typed languages?
Testing. Check out Test Driven Development, Coveralls, and Red-Green-Refactor.
Basically, everything that happens in an application should by tested. If you want a new feature, you write a test first. Slowly add code until the test passes, and then you know your application is still working.
It basically frees you up to make any changes to your code, and as long as all of the tests pass, you know the changes you made are okay.
What kind of container? One I invent myself? One from a different library? The same library? A map? A set/vector/array? Any object defining begin and end? Any object implementing Iterable?
You are not afraid of using templated functions, do you? And templates uses duck typing: you can pass anything which looks like compatible object.
When you writing function which takes input iterator you do not fear that somebody will pass this class:
OK, now that I know there is a Container concept that makes me feel better. All the tutorials I've read to try and understand Python don't mention any such concepts, however.
How does it work? I can understand small projects, but anything large seems like it would quickly get out of hand and fall into chaos. How do people write code at all in weakly typed languages?
That's why you make something large out of a bunch of smaller modules. Each module is self contained. Nothing falls into chaos because each module is simple to understand internally by looking at it, and when looking at the larger picture, you only need to consider each module as a black box. You do need good documentation though because of the ambiguity of having no type associated with the variable.
Where things can get crazy is when people start introducing variables such as info, which are used all over the place to represent json objects where it is elusive which properties the object should have.
While you can successfully write very large projects in javascript and maintain clear code and good organization, many people write horrible javascript that is a nightmare to use. Personally I do not even think that idiomatic javascript is good.
Basically if you use json objects, then name them well, and keep a corresponding documentation of the properties, what they are for, and when they are necessary.
"advantages" of dynamic languages over statically typed ones I could think of are:
1. it is much easier to implement a compiler/interpreter - no typechecking phase, which is one of the most complex phases
2. the type system does never get in your way - this is useful in very rare edge cases, where in a statically typed language you'd have a correct program that would not type check successfully.
The biggest drive behind dynamic typed languages are statically typed languages with verbose and inexpressive static type systems like Pascal or C++ (and Java/C# not much better really), where you very often need to do type casting to shut up the compiler.
You can look through the commits to see the development process. With the test in place, if there ever is an edge case, I just add that case to the list of assertions in the test and change the code until the tests pass. I can do anything I want with the code and I know everything is okay because I keep the tests passing.
As far as containers, the last commit include a method, range, something like this: range( 1, 10 )
Do I really care what type that method returns? I don't. All I care is that I will have the numbers 1 through 9 in some sort of collection.
The actual code I wrote"
1 2
for value in range( 3, int( sqrt( x ) ) + 1, 2 ):
# something with value
is the same thing as:
1 2
for ( int value = 3; value < sqrt( x ) + 1; value += 2 )
// something with value
I wrote a recursive folder walk for a job interview, this is it:
1 2 3 4
from os import walk
for path, directories, files in walk( '.' ):
for file in files:
print path + '/' + file
How are you supposed to know you need three things (path, directories, files) for iterating the result of walk? Do you just have to consult documentation every single time or memorize it?
The first time I learned about walk, it was through reading documentation.
Besides memorizing, you can also use a command line interpreter:
1 2 3 4 5 6 7 8 9 10 11
$ python
Python 2.7.6 (default, Mar 22 2014, 15:40:47)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license"for more information.
>>> from os import walk
>>> for x in walk('.'):
... print x
... break
...
('.', ['.git', 'txt', 'tif'], ['find_diff.py'])
>>>
From that I can see I have three things, a string, a list of strings, and another list of strings.
If that's not enough, I can also get docs from inspect:
1 2 3
>>> import inspect
>>> print inspec.getdocs( walk )
documentation about how to use walk including examples
One can install ri documentation for Ruby:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
$ ri Array.each
= Array.each
ary.each { |item| block } -> ary
ary.each -> Enumerator
------------------------------------------------------------------------------
Calls the given block once for each element in self, passing that element as a
parameter.
An Enumerator is returned if no block is given.
a = [ "a", "b", "c" ]
a.each {|x| print x, " -- " }
produces:
a -- b -- c --
I'm just noting that these are higher level languages made for rapid development, you don't have to be as concerned about the types that you are using.
It was probably PHP. Depending on string content and operand order you can get contacenated string, integer sum or error. *Shudders* extreamely weak typing, strange operators properties...
Python will give you an error here.
Perl will try to convert string to integer with default value of 0 (like stoi() on C++)
One of the biggest leaps for me in javaScript was that nobody told me objects in JavaScript were actually just std::map<boost::any, boost::any>, so for a long time I had no idea why so much code was so inconsistent. Once I learned that objects are just maps of anything to anything else, it made a lot more sense to me but made me want to avoid the language at all costs.
True, but you can just as easily say "<Language> has some pretty weird quirks" because I've yet to see a language that doesn't have people pointing out problems with them.
@myesolar: You point out something to be concerned about, but I'm trying to get LB to realize that he doesn't have to worry as much :)
For example, a python number: x = 1
What is x, a char, an int, a double? How many bytes? Maybe it is stored as a c-string. These are things that are of little to no concern to the average application.