I've spent several hours now playing with magpie, and am beginning to love it. Most everything just makes sense. I have a few suggestions that can be taken with a grain of salt:
1. defclass - I know it is defining a class, and it sounds like CLOS, but I'm so used to other languages that the "def" seems redundant. What if it was just "class"?
2. I don't like using symbol vs keywords for everything, but I feel "is" could be replaced with "::" in type patterns. I feel it visually gives you separation, rather than having 3 words together (eg. "foo is Int" vs "foo :: Int") It's also what Dylan and Haskell uses.
3. Would it be possible to create class constructors without "new"? for Example, "Point(x, y)" instead of "Point new(x, y)". It's easy to define a method which does this, but it would be nice if this style of constructor was created when you define a class.
Here's an example of these 3 tweaks in action:
class Point var x var y end
def (this == Point) init(x :: Int, y :: Int) this init(x: x, y: y) end
val point = Point(x: 2, y: 3)
Subtle, but for me, makes it easier to visually read and parse. Of course, I could dig into the magpie code and try these out, but I wondered if anybody had any thoughts about them first.
Mike
It would also be easier to read with syntax highlighting, and I personally have no qualms with relying on syntax highlighting in this day and age to aid readability, so long as it's not completely unreadable without it.
I think :: will be too easily confused with type annotations (which it is in Haskell), when it is in fact pattern matching. I think "is" communicates this quite well - as soon as I saw it I thought "that's an odd choice to use for type annotations - ooh, wait, are they using pattern matching here?!"
> 3. Would it be possible to create class constructors without "new"? for Example, "Point(x, y)" instead of "Point new(x, y)". It's easy to define a method which does this, but it would be nice if this style of constructor was created when you define a class.
Personally I prefer the clean separation between a method and the slightly magic (though less so than a lot of other languages) object creation. Further, to me having a method that operates on the class makes perfect sense to me and fits all my mental models, whilst having a class behave like a method doesn't.
That was half of my point. They're not type annotations, they're pattern matching on type. There's a difference:
* The pattern matching doesn't give any type checking.
* Type annotations are limited to only to types. Pattern matching is a lot more flexible (silly example alert):
def (this == 0) isZero
true
end
def (this) isZero
false
end
Using something that looks like type annotations confuses the mechanics in people's minds and limits the scope of their ambitions as to what they can do with it.
Also, if you're used to "::" being type annotations - or even if not for that matter - this looks weird:
match foo
case :: Int then print("Int")
end
It'll become even more important if/when (I don't know the plans) actual type annotations come back. I think using the same symbol as other languages use for type annotations will confuse people a lot more. If type annotations do come back, I'd really like "::" to be used for it.
Of course, all my arguments are against using something that is used for type annotations in other languages. If you can come up with a good symbol that means "is of type" that isn't used for type annotations in other languages I may be on your side (I am used to symbol heavy languages, after all) but as it stands, I can't come up with one myself.
> 1. defclass - I know it is defining a class, and it sounds like CLOS, but I'm so used to other languages that the "def" seems redundant. What if it was just "class"?
I find defclass tedious too, and it was just class for a long time.
The problem is that classes are first class in Magpie so it's fairly
common to have a variable that holds a class. It's nice to be able to
call that variable "class". I always felt that "klass" and "clas" and
stuff like that was awkward in other languages.
One thing I noticed is that reserved words are a rarely complete
common nouns. They are either non-noun words like "while" and "for" or
abbreviations like "int" and "bool". That leaves as many nouns free as
possible for use as variable names. So the idea with "defclass" was to
free up "class".
I'm not crazy about it but I have gotten more used to it. I find
something strangely appealing about both methods and class definitions
starting with "def" but I'm open to other ideas. One possible one
would be to make "class" a contextual keyword, so you would do:
def class Foo
...
end
And in that context it would define a class, but it's otherwise
available for use as an identifier. That feels a bit fishy too,
though.
> > 2. I don't like using symbol vs keywords for everything, but I feel "is" could be replaced with "::" in type patterns. I feel it
> visually gives you separation, rather than having 3 words together (eg. "foo is Int" vs "foo :: Int") It's also what Dylan and
> Haskell uses.
> I also find :: easier to parse, though that may just be because of my experience with languages that tend to prefer symbols over words.
I went back and forth between those for a while. I think :: was the
winner at first. I ultimately went with "is" because:
1. Magpie generally prefers words over punctuation ("end", "then", etc.)
2. "is" isn't any longer than "::".
3. It reads well and explains exactly what it means.
I find syntax highlighting is critical, though. I have some crappy
TextMate bundle slapped together that highlights "is" and that makes a
world of difference. Without syntax highlighting, Magpie quickly
becomes a wall of text.
> 3. Would it be possible to create class constructors without "new"? for Example, "Point(x, y)" instead of "Point new(x, y)". It's easy to define a method which does this, but it would be nice if this style of constructor was created when you define a class.
I like that about Python. I went with a single "new" method even
though it's less terse for one main reason: It makes construction
"first-class". In other words, you can do this:
def makeThing(class, arg)
class new(arg)
end
By making a single "new" method that takes the kind of object to
create as an argument, you can make object construction...
parameterizable? If we just made methods for each class name, you
wouldn't have an easy way to construct an object generically.
That being said, you're of course always free to make a little helper
method that instantiates a class. The regex module has exactly that so
you can do:
regex("foo")
instead of:
Regex new("foo")
> I think :: will be too easily confused with type annotations (which it is in Haskell), when it is in fact pattern matching.
I think of it more or less as both. Strictly speaking it is indeed a
pattern, but it conveniently also identifies the type of a variable,
so you could treat it as a type annotation too.
> On a side note, how far can we take immutability in magpie? Should I define the above sample as something like this instead?
Take it as far as you want, but don't feel you need to. I find
mutability really convenient as small scales and within a single
thread, but problematic across large programs or when concurrency is
involved. So my plan is that Magpie will have nice language support
for immutability and will ensure that there is no shared mutable state
across threads. At the same time, it has friendly mutable collections
(list) and has no problems with classes that have mutable fields.
I want immutability to be a tool you can use when you want (and I want
Magpie to make it easy to actually express immutability), but not
something you have to do to please the language.
> It'll become even more important if/when (I don't know the plans) actual type annotations come back. I think using the same symbol as other languages use for type annotations will confuse people a lot more. If type annotations do come back, I'd really like "::" to be used for it.
"Plan" is too strong a word for it, but my long term hope is that
patterns could be used directly for static analysis too, so you
wouldn't need a separate type annotation syntax. Because pattern
matching combines both testing (and you can test for type) and
variable binding, that gives you all you need to know "foo is of type
Bar", which sounds like a type annotation to me.
Once you start really thinking about types (generics, etc.) it gets a
lot more complex which is why I'm not worrying about it now, but I'm
hoping that just type-based patterns will be enough to get some of the
benefit that static types give you in other languages. At the very
least, I find type patterns help document what my methods expect, and
I really like being able to define methods and know that they will
only be called if their arguments are of the right type.
All I'd want beyond that is some static analysis for finding some
errors, and being able to use dataflow analysis to generate better
code. Given how hilariously primitive Magpie's current implemention
is, though, that's a good ways off. :)
Cheers!
- bob