<div dir="ltr"><div><div><div><div><div>Wow! The suggestion of static typing instead of python-style dynamic typing surprised me, but after carefully reading your argument for it, I think I agree. I trust your judgment on this, and it seems like it will actually make forwards/backwards compatibility easier, and the inclustion of the Any type means I can still do as much dynamic typing nonsense as I please :)<br><br></div>I like the idea of having Number as the default type instead of Any.<br><br></div>As for declaration syntax... after reading all those I think cast my first vote for something like:<br><br></div><span style="font-family:monospace,monospace">script, <Slice> return me some slice, <String> string arg, <Attack> attack arg, begin</span><br><br></div>But I could live with many of the other syntaxes you suggested, I just think this one looks cleanest to me.<br><br></div>I also dislike the idea of being flexible about whether the type comes before or after. Just because <bracketing> makes it possible, doesn't mean it is a good idea.<br><div><div><div><div><br></div><div>Bonus argument in favor of <Typename> is that Mogri turned off html by default in forum posts so we could actually use <Typename> without copy-paste agony ;)<br><br></div>---<br></div><div>James "Feeling Pretty Excited About This" Paige<br></div><div><br></div></div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Aug 23, 2016 at 10:45 AM, Ralph Versteegen <span dir="ltr"><<a href="mailto:teeemcee@gmail.com" target="_blank">teeemcee@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">I'm finally resuming work on designing and implementing the major new<br>
version of HamsterSpeak (which I call HS4) which adds types and object<br>
orientation, while being backwards-compatible.  I'm looking for<br>
feedback in the design of the language. This email discusses the type<br>
system and specifically how type annotations might work.<br>
<br>
May as well state that the main goals of HS4 are:<br>
- Easy to learn. Should be:<br>
-- as simple as possible<br>
-- similar to popular languages<br>
-- consistent, including with existing HS idioms<br>
- Easy to use:<br>
-- features you expect in modern languages, like arrays, dicts and<br>
   strings with various handy methods<br>
-- easy to avoid bugs and to debug<br>
-- features useful for scripting games (hooks and extensible builtin<br>
   objects, script fibres, signalable and pauseable scripts (e.g. tied<br>
   to an npc or map), and live-reloading of scripts)<br>
- Backwards compatibility<br>
-- it's OK if a couple features are toggled off with backcompat<br>
   bitsets or other means, most notably necessary for script<br>
   'multitasking', but existing scripts should not need modifying<br>
   except in exceptional cases (e.g. new keywords)<br>
<br>
<br>
For years, the plan has been for HS4 to be a dynamically typed<br>
language, but in the intervening years I've been using Python and<br>
other dynamic languages heavily, and as a result now really appreciate<br>
what a great thing static typing is, for catching bugs and improving<br>
code readability.<br>
<br>
If we add OO methods as alternatives to existing functions then<br>
 set slice velocity(sl, 10, 10, 5)<br>
could be written<br>
 sl.set velocity(10, 10, 5)<br>
Then what happens if you typo the function/method name or pass invalid<br>
arguments?  Currently HSpeak can catch typo'd names and at least check<br>
the number of arguments.  But if everything is dynamic, the typo<br>
wouldn't be detected until you run the script. This would be a huge<br>
step backwards. The goal is to help users eliminate bugs (people<br>
frequently pass invalid arguments to commands, like mixing up hero IDs<br>
and party slots), but we would be encouraging them.<br>
<br>
Therefore I propose adding syntax to declare the types of variables<br>
(including locals, globals, and builtin command and script arguments<br>
and return values), and that builtin types/classes and user defined<br>
types (UDTs) be statically defined in a hss/hsd file.  Then HSpeak<br>
will be able to verify that accessed methods and members actually<br>
exist, and would also be able to check that sensible arguments are<br>
passed to scripts, which will catch a large class of bugs.  There will<br>
also be an 'any' type, which prevents type checking but lets you do<br>
whatever you want at runtime.  I recommend that variables that aren't<br>
annotated with a type default to 'number' instead of 'any', so that<br>
you have to explicitly ask for dynamic typing. Otherwise people will<br>
default to not declaring types for anything, and thus would be<br>
susceptible to bugs.<br>
<br>
I'm not proposing a rich strict type system lets you be type-safe all<br>
the time.  That means no "algebraic" nested type expressions such as<br>
templates/generics (parametrised types) or C's function pointer types<br>
which specify argument types.  Well, as an exception, it would be nice<br>
to also support a more refined 'array(attack)' type, although the<br>
'array' type would simply default to an array of 'any'.  Calling<br>
callbacks (function types) is uncommon, so typing them seems unnecessary.<br>
<br>
I also propose being lenient with type conversions so that there's no<br>
need to use explicit casts (or to even add them to the language):<br>
 - Clearly all types should automatically convert to an 'any' variable<br>
 - An 'any' value could automatically convert to anything else<br>
 - All existing script commands that expect ID numbers or handles work<br>
   with objects too, and vice-versa.<br>
Maybe we could even also implicitly convert integers into types for<br>
builtin objects with ID numbers, e.g.:<br>
  variable([attack] atk)   # See below about declaration syntax<br>
  atk := 3<br>
  show string(<a href="http://atk.name" rel="noreferrer" target="_blank">atk.name</a>)<br>
This looks a bit evil, but a more realistic example why you might want<br>
such a thing is:<br>
  script, npc dances, [npc] who, ( ... )<br>
  ...<br>
  npc dances(3)  # First NPC with ID 3<br>
Or if not, just require an explicit like "atk := get attack(3)".<br>
I'm leaning towards that, but also want the autoconversion in the<br>
second example, and don't know how to reconcile them.<br>
<br>
If type definitions are static then polymorphism requires inheritance<br>
(probably explicitly declared ("nominal" rather than "structural")).<br>
Unless you just use 'any', of course. It could also be possible to<br>
allow adding new members and methods to objects via an 'any'<br>
variable. Of course, then you have no error checking at run-time<br>
either, so something more explicit than "x.y := z" could maybe be<br>
required.<br>
<br>
==Syntax==<br>
<br>
I can't actually decide on the syntax for declaring types, which is<br>
not easy to decide because of white-space insensitivity.  I also want<br>
to avoid any use of commas or parentheses, which would be confusing<br>
and likely ambiguous in script argument lists.  Also, note that we<br>
will want builtin types like 'npc', 'item', 'hero', etc.  Since these<br>
are all very common variable names, type names would have to live in a<br>
separate namespace (like in FreeBasic) and the type ought to stand out<br>
when written. Alternatively (although not entirely different) type<br>
names could start/end with a special character, such as "!Hero".<br>
Capitalising type names by convention would also help.<br>
<br>
Broadly, some different options are:<br>
(recall I suggested 'Number' be the default, hence optional)<br>
- variablename separator typename<br>
   script, dup item, item !Item, times !Number = 1, begin<br>
   # Julia uses the following<br>
   script, dup item, item ::Item, times ::Number = 1, begin<br>
   script, dup item, item *Item, times *Number = 1, begin<br>
   script, dup item, item -> Item, times -> Number = 1, begin<br>
- typename separator variablename<br>
-- e.g.<br>
   script, dup item, Item! item, Number! times = 1, begin<br>
   script, dup item, Item:: item, Number:: times = 1, begin<br>
   script, dup item, Item/ item, Number/ times = 1, begin<br>
   script, dup item, Item.item, Number.times = 1, begin<br>
- bracketed-typename variablename  (or the reverse)<br>
-- e.g.<br>
   script, dup item, [item] item, [number] times = 1, begin<br>
   script, dup item, /item/ item, /number/ times = 1, begin<br>
   script, dup item, <item> item, <number> times = 1, begin<br>
   script, dup item, "item" item, "number" times = 1, begin<br>
   Note that in this case we could allow putting the type before or<br>
   after as you wish (then you don't need to remember where it goes)!<br>
- something that looks like a keyword<br>
-- e.g.<br>
   script, dup item, item .is Item, times .is Number = 1, begin<br>
     As a bonus, "is XYZ" could be actual methods/functions for checking type:<br>
     if (<a href="http://x.is" rel="noreferrer" target="_blank">x.is</a> number) then (...)  # Seems to imply everything-is-an-object<br>
                                  # even if that's not the case.<br>
     if (is number(x)) then (...)<br>
   script, dup item, item 'as item, times 'as Number = 1, begin<br>
   script, dup item, item "is item", times "is number" = 1, begin<br>
<br>
':' is already heavily used as part of identifiers so unfortunately<br>
couldn't be used as a separator, unless it was something like "::".<br>
It might look like "item:Hammer" includes the type, but the "item:" part<br>
is part of the name so an actual typed declaration would look something like<br>
  variable(item::item:Hammer)  # yuck<br>
<br>
==Syntax for script return types==<br>
<br>
The syntax for declaring locals and globals could be the same, e.g.<br>
  variable([any] tmp, [Slice] sl1, idx)  # idx is a Number, not a Slice<br>
but declaring the return value of a script is a different matter. E.g.<br>
  # Don't like this<br>
  script, [Slice] create shadow, [Slice] from what, length, begin<br>
  # Putting it afterwards demands consistency<br>
  script, create shadow [Slice], from what [Slice], length, begin<br>
  script, create shadow -> Slice, from what -> Slice, length, begin<br>
  # Unless we allow any order<br>
  script, create shadow "Slice", "Slice" from what, length, begin<br>
The return type could be put somewhere else, e.g.<br>
  script -> Slice, create shadow, from what -> Slice, length, begin<br>
Or there could be a pseudo-argument named "return" that goes in the<br>
argument list<br>
  script, create shadow, return "Slice", from what "Slice", length, begin<br>
  script, create shadow, [Slice] from what, length, [Slice] return, begin<br>
Or we could change the syntax for script definitions:<br>
  script, create shadow ([Slice] from what, length) -> Slice, begin<br>
<br>
-> X is especially common syntax for the return type of a<br>
function. (But note that in type theory and functional languages "X -> Y"<br>
is notation for the type of a function taking an X and returning a Y)<br>
______________________________<wbr>_________________<br>
Ohrrpgce mailing list<br>
<a href="mailto:ohrrpgce@lists.motherhamster.org">ohrrpgce@lists.motherhamster.<wbr>org</a><br>
<a href="http://lists.motherhamster.org/listinfo.cgi/ohrrpgce-motherhamster.org" rel="noreferrer" target="_blank">http://lists.motherhamster.<wbr>org/listinfo.cgi/ohrrpgce-<wbr>motherhamster.org</a><br>
</blockquote></div><br></div>