C/C++ interop and OS interactions are separate issues mostly orthogonal to type systems.
Teaching would probably start without using the type annotations for simplicity. Let the students get something working first with basic dynamic code. Then teach the type annotations and reasons for using them in more advanced courses.
sub add(\number1, \number2) { number1 + number2 }
If you call `add` with simple numbers it works: say add(1, 2) # 3
Other types of number too: say add(0.1, 0.2) == 0.3 # True
It works even for newbie definitions of "number": say add('0.1', '0.2') == '0.3' # True
A sufficiently determined newbie can of course break `add`: say add('foo', 'bar') == 'waldo'
The program stops with a suitable error message ("Cannot convert string to number ...").----
The student moves on to a more advanced course...
----
Type annotations are introduced:
sub add(Numeric \number1,
Numeric \number2) { number1 + number2 }
Everything still works as expected: say add(1, 2) # 3
But we get better error checking: say add('foo', 'bar') == 'waldo'
This generates a compile-time type-checking error ("Calling add(Str, Str) will never work with declared signature (Numeric \int1, Numeric \int2)").So, reason 1 for using types: get type-checking that catches errors at compile-time.
You can use native types for closer-to-the-metal speed (compact representations, no automatic overflow checking, etc.):
sub add(num64 \number1,
num64 \number2) { number1 + number2 }
`num64` corresponds to C's double float datatype representation. This sub will likely outperform the versions of `add` that do not have natively typed parameters.A third reason for explicit types is to take advantage of C interop:
use NativeCall;
sub add(int32, int32) returns int32 is native("calculator") { * }
If you've got a local C library (called "libcalculator.so" or somesuch) then this: say add(1,2)
will call the function with the symbol name `add` in that library.And so on.
At one point you do have to make a decision though. If you come from a static type system, the compiler rejects programs if it can't proof their type correctness. Dynamic languages that introduce statics types typically do it the other way 'round: in case of doubt, allow the program at compile time, and possibly throw a type exception at run time.
You can try to make separate decisions in separate scopes, but then you have problems at the boundaries between such regions.
The point I'm trying to make is that gradual typing comes with its own complexity, both on the implementation side and through cognitive load for the programmer.
It doesn't have to be any harder than a language with a JIT VM. See Strongtalk and Dart.
At one point you do have to make a decision though. If you come from a static type system, the compiler rejects programs if it can't proof their type correctness. Dynamic languages that introduce statics types typically do it the other way 'round: in case of doubt, allow the program at compile time, and possibly throw a type exception at run time.
Also wrong. See Strongtalk and Dart. If you wanted to, you could make a variant of either system not compile your app without every type specified.
Like tightening the bolts. This is a really interesting idea. I could also envision a utility wizard that you could run on a piece of code that could help guide you through making things more specific by asking you questions about the code. Are tools like this out there already? Like if you've defined a string and you run the utility it would ask: “Is this variable a number? Yes/No.” and then change to ensure it's a number in your source?
EDIT: Found one for you:
This is the Perl 6 view. See "Getting beyond static vs. dynamic" http://www.jnthn.net/papers/2015-fosdem-static-dynamic.pdf
In Perl 6:
> 1. A value.
sub (\var) { say var }
> 2. A number. sub (Numeric \var) { say var }
> 3. A floating point number. sub (Num \var) { say var }
> 4. A floating point number between 0.0 and 100.0. sub (Num \var where 0.0 .. 100.0) { say var }
> 5. A floating point number between 0.0 and 100.0, and optimize for runtime performance instead of precision. sub (num \var where 0.0 .. 100.0) { say var }
> Ada and Microsoft Visual Basic incorporate some elements of this concept but didn't take it far enough.Did they take it as far as Perl 6 per the above?