Arc Forumnew | comments | leaders | submitlogin
2 points by rocketnia 4774 days ago | link | parent

"what about code that expects something of type 'table?"

I blame that code for its lack of extensibility. It should just go ahead and use the value as a table, trusting the extensions to be there (and using failcall to recover, of course ^_^ ).

If it must do a boolean check to determine the value's features (perhaps because failcall isn't available, or because it needs to fail fast), it shouldn't do a direct type check. Instead, it should call another global function dedicated to the inquiry of tableness (which is probably too specific an inquiry anyway, most of the time). That way, people can extend the tableness function too.

Extensibility isn't the only benefit of avoiding [isa _ 'table]. It also becomes possible to have a single value that supports table operations and (say) input stream operations at the same time. It's probably a silly combination, but a custom type based on an association list could warrant it.



1 point by Pauan 4773 days ago | link

You're missing the point... the problem is not when the function expects something of type table... it's when the function needs to change it's behavior based on the interface. Consider `each`. It needs to change it's behavior depending on whether it's a table or a cons or a string. How is using (table? foo) better than (isa foo 'table)? Both are the same as far as extensibility goes. And in fact, you can do that right now, in Arc:

  (def table? (x) (isa x 'table))
And you're also missing the whole point of message passing... message passing enables duck typing, which means it's possible to write a function that doesn't care what it's type is, as long as it supports the required message.

You're trying to solve the symptom... I'm trying to solve the problem. What I'm saying is that re-extending all the relevant built-ins is ridiculously inefficient and verbose, and that there's a far better way. Message passing not only drastically reduces verbosity, but it also solves the problem you mentioned.

I suggest you go and read http://arclanguage.org/item?id=14237 which already explains this in more depth.

I think the current way that people think about types is fundamentally wrong, and I'll write a post about that in a moment.

Edit: here's the post http://arclanguage.org/item?id=14261

-----

1 point by rocketnia 4773 days ago | link

"Consider `each`. It needs to change it's behavior depending on whether it's a table or a cons or a string."

Yes. In a world with failcall, it can try treating the value as a table in one rule, as a cons as another rule, and as a string in a third rule. In a world without failcall, it can do the same thing, but with the help of extensible global functions 'atable, 'acons, and 'astring. That's merely a specific example of what I just said.

---

"How is using (table? foo) better than (isa foo 'table)? Both are the same as far as extensibility goes."

Sure, there's not a whole lot of difference between extending 'table? and extending 'isa. However, in my mind 'isa has a clear role as a way to check the most specific possible feature of a value: the kind of internal data it has.

One could go all the way down, making a (deftype wrap-foo unwrap-foo isa-foo) form that eliminates the need for 'annotate, 'rep, 'isa, and 'type altogether. In this example, 'isa-foo would be a function that indicates support for 'unwrap-foo, and 'wrap-foo would be a simple data constructor that makes an encapsulated value with nothing but innate support for 'unwrap-foo. (In a system with failcall, 'isa-foo is pretty much redundant.)

This is basically how the Kernel draft deals with custom types (except without an eye toward extensibility), but I haven't been inspired to go quite as far as this in practice. I think programmers should be free, if discouraged, to break encapsulation of values they don't know the nature of, like Arc programmers can when they use 'type and 'rep.

"And in fact, you can do that right now, in Arc[...]"

Cool, huh? :-p

Obviously pg-Arc hasn't been built from the ground up this way, but Arc Forumgoers have had an awful lot of extensibility ideas since Arc 3.1 was released, and pursuing any one of them in Anarki would change the core so much as to turn it into a separate language. That's why I don't call Penknife a version of Arc.

---

"And you're also missing the whole point of message passing... message passing enables duck typing, which means it's possible to write a function that doesn't care what it's type is, as long as it supports the required message."

That's the whole point of extending global functions too. I don't care what something's type is, as long as all the utilities I use have been extended to deal with it.

As I mentioned above with 'deftype, the 'extend approach can go all the way down to the level of making the 'type function itself merely a reflection tool. Obviously pg-Arc isn't built this way, but we've had an awful lot of extensibility ideas here since Arc 3.1 was released, and pursuing any one of them in Anarki would practically turn it into a separate language. (That's why I don't call Penknife a version of Arc.)

---

"I suggest you go and read http://arclanguage.org/item?id=14237 which already explains this in more depth."

I've already read that, thanks. I just wasn't convinced, and I found more interesting arguments to make over here. ^^

"Edit: here's the post http://arclanguage.org/item?id=14261 "

My next order of business is to read that.

-----

1 point by Pauan 4773 days ago | link

"Yes. In a world with failcall, it can try treating the value as a table in one rule, as a cons as another rule, and as a string in a third rule."

How? I've provided concrete examples where my solution is significantly shorter at creating new data types than the current solution, while still retaining `isa`, while avoiding problems. If you have a solution that can do all that, then please present it.

---

"In this example, 'isa-foo would be a function that indicates support for 'unwrap-foo, and 'wrap-foo would be a simple data constructor that makes an encapsulated value with nothing but innate support for 'unwrap-foo. (In a system with failcall, 'isa-foo is pretty much redundant.)"

Why? My system already does things similar to that, but in a very simple way, that's compatible with pgArc.

---

"However, in my mind 'isa has a clear role as a way to check the most specific possible feature of a value: the kind of internal data it has."

This is precisely what I meant when I said that I think the current view of types is fundamentally wrong. A table is not a hash. It's an interface that could potentially be implemented as a hash... or something else. Arc leaves it unspecified, which I consider to be a Good Thing.

---

"That's the whole point of extending global functions too. I don't care what something's type is, as long as all the utilities I use have been extended to deal with it."

...but as I've already mentioned repeatedly (and demonstrated in a post), that way is significantly more verbose than it has to be. My solution solves that, in a way that is more hackable/extendable/succinct. That is the goal of Arc, yes? Hackability and succinctness? I still have not seen a solution that matches mine for succinctness, let alone extensibility. Please provide one, if you're not convinced that my way is superior. Then I will back down.

-----

1 point by Pauan 4773 days ago | link

By the way, I just noticed something. Check out this link: http://wiki.call-cc.org/Python-like%20generators

Note that they're using the message-passing idea: after an iterator has been created, you can call it with 'status?, 'dead?, 'alive?, or 'kill! to get/set it's private data.

What I'm suggesting is to treat all compound data types like that. You can then create function wrappers around them, which is in fact what they did too: note the definition of `iterator-empty?`

Every individual iterator has it's own private state, so it doesn't make sense to require extending built-in functions every single time you create a new iterator. Instead, you define a function wrapper (like `iterator-empty?`) that accesses the internal data for you. No need to extend anything! That conciseness is what message passing gives you.

-----