Arc Forumnew | comments | leaders | submitlogin
2 points by nex3 5892 days ago | link | parent

I totally agree. One of the things I like most about Ruby and its type system is that it puts so much emphasis on has-a relationships. This is pretty much what I'm going for with stuff like redef, defm, and my formulation of settable-fn... even though they actually use is-a to check, the idea is that only certain basic functions - analogous to methods like #each in Ruby, or the instance functions of Haskell type classes[1] - need to use is-a to check, and all other functions assume that the basic functions work.

[1] I'm not that familiar with Haskell terminology, so this might be wrong.



3 points by almkglor 5892 days ago | link

[1] This is about correct; Haskell dispatches off the is-a ness of the type. However, code you write will generally ask for the has-a relationship:

  {- merge used for mergesort -}
  merge :: Ord a => [a] -> [a] -> [a]
  {- The "Ord a" above asserts that the type "a"
     should be an "Ord"inal, i.e. it should support
     < <= > >= == methods
  -}
  merge [] [] = []
  merge a []  = a
  merge [] b  = b
  merge a:as b:bs
        | a < b     = a:(merge as b:bs)
        | Otherwise = b:(merge a:as bs)
  {- Of course, I haven't programmed Haskell in a while,
     so the above code might be wrong. -}
If we had has-a relationships, we might say something like this in Arc:

  (def merge (a b)
    (unless (and (has-a (car a) 'Ord)
                 (has-a (car b) 'Ord)
                 (is (type a) (type b)) )
      (err "Type error, needs Ord"))
    (if
      (no a)
        b
      (no b)
        a
      ; now we're assured < works
      (< (car a) (car b))
        (cons (car a) (merge (cdr a) b))
        (cons (car b) (merge a (cdr b))) ))
Hmm. LOL. I can just imagine a macro to do that type checking for you:

  (type-check (list a b)
     (Ord a) ((a . as) (a . as)))
It's beginning to look lot like Haskell ^^. Heck. arc.arc is congruous to Haskell.Prelude

-----

4 points by nex3 5892 days ago | link

Yeah, I've seen several ways to express has-a relationships. Statically typed languages like Haskell tend to express them as is-a relationships (e.g. Int is-a Ord), since that meshes well with type safety. Languages that embrace duck typing, like Ruby, tend to make has-a relationships implicit; just use the method (or in Arc's case, function) and assume that the receiver will react properly. This meshes well with the late-binding, screw-static-verification philosophies of these languages, which Arc generally shares, and the message-passing object model, which Arc does not.

This is where I assume Arc will end up building its type system, if it ever does embrace a single type philosophy[1]. Even if it doesn't have a message-passing model, its dynamism makes the implicit has-a model a good fit.

The only language I've seen that embraces explicit checks for has-a relationships, as opposed to expressing them as is-a or making them implicit, is Javascript. This is mostly because you're dealing with objects that have an inherently variable and ill-defined interface that you don't know a lot about at compile-time. I think most JS developers view it as an annoying necessity, though, so I'm inclined to believe it's the least pleasant way of dealing with has-a (despite being the most explicit).

[1] Speaking of which, I really think it should. This is sort of implicit in taking part in all these discussions about typing, I suppose, but I wanted to mention it anyway. Any sufficiently powerful, has-a-based type system won't be a constraint on the language, but will rather allow powerful abstractions like Ruby's #each and almkglor's scanner.

-----