On Sat, Apr 30, 2016 at 11:13 AM, Mo Jia <
life....@gmail.com> wrote:
> But In my understand. Point1 Point2 is different data type. I can
> have same name constructor function to build a point in their type.
> And I can using the same name. Because the constructor is in the type
> Point2 or Point1. It may not be defined in the same namespace.
This is precisely correct.
Point1 and Point2 describe different data types. The only thing
stopping them both being declared in the same module is that Pyret
doesn't allow the same identifier to be bound twice in the same scope.
So there's no restriction that two datatypes cannot define
constructors with the same name: it's strictly a scoping rule.
We could define Point1 and Point2 in different modules, and tell them
apart. Here's an example:
https://code.pyret.org/editor#share=0B32bNEogmncOX0VkbEo0cmU1RFE
That module imports the following one, which defines Point1, which
also has a point constructor:
https://code.pyret.org/editor#share=0B32bNEogmncOODl3bnYxVHNONkE
The tests in the first file show that Point1's point is different from
Point2's point, despite them having the same constructor name and
fields.
On Sat, Apr 30, 2016 at 6:29 PM, Izzet Pembeci <
pem...@gmail.com> wrote:
> If Pyret was statically typed like C++, Java this may be allowed because the
> context will determine which point(...) to be used:
Indeed, type information could make this work, though even with the
type checker on, Pyret disallows two constructors with the same name
to be declared in the same scope. This is a conscious decision in
Pyret's design to keep scope simple and avoid errors due to unintended
shadowing and redefinition of names.
> By the way don't think point(...) as a constructor function. Think them like
> labels marking the kind of a value which belongs to a particular data type.
The label perspective is indeed quite useful to understand how "cases"
works in Pyret, thanks for pointing this out.
It's worth mentioning that in Pyret, "point" and other constructors
created by data definitions are actually functions, and can be passed
around or stored in other places as values like any other function.
That said, the label perspective is the right one to take for working
with data in the vast majority of situations.
======
As a little aside, I got curious about the behavior of this in a
closer cousin of Pyret. In OCaml, it's not an error to write:
type point1 =
| Point of int * int
type point2 =
| Point of int * int
let (x : point1) = Point(5, 6);;
let (y : point2) = Point(2, 4);;
There's an interesting limit to the lengths type inference will go
here, though. If we write:
let z = Point(5, 6);;
let (w : point1) = z;;
We get an error:
Error: This expression has type point2 but an expression was expected of type
point1
Because the second Point constructor is chosen by type inference,
ascribing the point2 type to z, and causing the binding on the next
line to fail as a result.