Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

should the trait shortcut permit non-type parameters? #58

Closed
kjx opened this issue Feb 17, 2016 · 18 comments
Closed

should the trait shortcut permit non-type parameters? #58

kjx opened this issue Feb 17, 2016 · 18 comments

Comments

@kjx
Copy link
Contributor

kjx commented Feb 17, 2016

Here is a variable in a trait:

class cell(initial) {
   var value := initial
   method get {
       value
   }
   method set(x) {
       value := x
   }
}

trait has_var_a(x) {
   uses has_var_a'(cell(x))
}

trait has_var_a'(c) {
   method a {
       c.get
   }
   method a:=(x) {
       c.set(x)
   }
}

def o = object {
   uses has_var_a(1)
}
print(o.a)
o.a := 999
print(o.a)

Here is a side effect:

print "Side effects:"

trait noop(x) { }
trait printer {
   uses noop({
       print(self)
       1
   }.apply)
}
def p = object {
   uses printer
}
print(p)
@kjx kjx added the 1:now label Feb 17, 2016
@apblack
Copy link
Contributor

apblack commented Feb 19, 2016

I'm not clear what point the above program is intended to illustrate.

As I though I had posted here already (but can't now find!), the issue is not traits taking parameters, but traits being given non-manifest arguments. We agreed at Pomona that traits should be manifest. That should mean that either they don't have parameters at all, or that any (type or object) parameters they do have must be instantiated with manifest arguments.

So I answer the question in the issue title affirmatively. But the trait instantiations above are still illegal.

@kjx
Copy link
Contributor Author

kjx commented Feb 19, 2016

I'm not clear what point the above program is intended to illustrate.

I recall (from Michael's explanation in the teleconference) that the rules on not having code or state in traits can be surmounted with these kinds of constructions.

or that any (type or object) parameters they do have must be instantiated with manifest arguments.

I don't see any non-manifest arguments in the above example - but I'm not sure what definition of manifest you are using! Talking to Michael this afternoon, we got to something like the structure of the a manifest expression can be determined before any code starts running. I think that applies here.

But the trait instantiations above are still illegal

Why? I'm not trolling: I'm just not sure which instantiations you consider illegal, and why

@apblack
Copy link
Contributor

apblack commented Feb 19, 2016

I broke the initial example into two separate examples. Presumably, these are trying to illustrate separate things. Something bad happens, right? Could you please explain what the bad thing is in the first example. We know that we can have (hidden) state in a trait — that's a deliberate design choice. That's why we designate the object produced by

method uid {
    def myuid = Singleton.new
    object {    // meets the restrictions to be trait object
        method uid { myuid }
    }
}

as being a trait.

In the second example, the bad thing is that the trait composition of printer and noop, which we want to happen at compile time, prints something at runtime. I agree that's bad, and I believe that it is excluded because the argument to noop isn't manifest. I don't know what rules of "manifestness" you are applying, but

{       
    print(self)
   1
}.apply)

doesn't look manifest to me.

@kjx
Copy link
Contributor Author

kjx commented Feb 22, 2016

We know that we can have (hidden) state in a trait

from a brief talk to Micahel, I think that is the "bad thing" in the first example
It raises the question of why we do not permit implicit state in traits.
My answer is: although our semantics could cope with it, the corner cases are confusing, and ruling out explicit state (as implicit state must be initialised before trait creation begins) also rules out a bunch of corner cases.

doesn't look manifest to me

if "manifest" means the "shape" of the final result can be determined before the code really starts running, or that the code does not depend on mutable state, including input then that code, while rather ugly, would be manifest.

@apblack
Copy link
Contributor

apblack commented Feb 22, 2016

I don't understand either of your points above. We do allow implicit state; I don't know what "mutable code" is. Let's leave this for the teleconference.

@kjx
Copy link
Contributor Author

kjx commented Feb 24, 2016

This seems to have devolved into a discussion of manifest, which is in #47.

This is just a detail of the "traits shortcut". Should non-type parameters be permitted?

@apblack
Copy link
Contributor

apblack commented Feb 26, 2016

It would seem inconsistent not to support type parameters in the trait shortcut, since once can get the same effect using a method that has a parameter, and whose body is an object constructor that captures the parameter and meets the trait restrictions.

However, @kjx and Michael Homer seem to have examples that show that parameters are problematic. I'm therefore reluctant to make a decision until someone explains what the problem is. Hence, my desire to leave this for the teleconference.

@kjx
Copy link
Contributor Author

kjx commented Feb 26, 2016

We have to support type parameters in the trait shortcut (or otherwise we have to give up on (generic) static typing; give up on traits; or just give up). The question is whether we support non-type parameters.

I'm therefore reluctant to make a decision until someone explains what the problem is.

The presenting problem is that parameters offer yet another way to arrange "traits" that have state and complex stateful initialisation semantics, as per the examples above.

The underlying problem is that if traits have state and complex stateful initialisation semantics, why do we now have two inheritance-like mechanisms and two class-like shortcuts instead of just one of each?

@KimBruce
Copy link
Contributor

I prefer only type parameters to traits.

Kim

On Feb 25, 2016, at 5:59 PM, kjx notifications@github.com wrote:

We have to support type parameters in the trait shortcut (or otherwise we have to give up on (generic) static typing; give up on traits; or just give up). The question is whether we support *non-type parameters.

I'm therefore reluctant to make a decision until someone explains what the problem is.

The presenting problem is that parameters offer yet another way to arrange "traits" that have state and complex stateful initialisation semantics, as per the examples above.

The underlying problem is that if traits have state and complex stateful initialisation semantics, why do we now have two inheritance-like mechanisms and two class-like shortcuts instead of just one of each?


Reply to this email directly or view it on GitHub #58 (comment).

@kjx
Copy link
Contributor Author

kjx commented Feb 26, 2016

If Andrew's happy with that then I guess we can accept and move on.

Or we could consider

  • how many method like things do we want with different rules?
  • which rules should be enforced in the core, and which in dialects?
  • what principles do we adopted to make the above two decisions

For example, given the following principles:

  • "Symmetry is a complexity-reducing concept ... seek it everywhere" (Perlis 6th Epigram)
  • GW Bush: "You should be able to run any program ... Even those that are guaranteed to fail a counter-example is [sometimes as useful as] a type-error message"

Then the answers would be:

  1. we want few things with common, simple, general rules
  2. as few rules as possible constraining the core; exceptions and as many rules as possible in dialects.

@kjx
Copy link
Contributor Author

kjx commented Mar 7, 2016

@KimBruce
Copy link
Contributor

KimBruce commented Mar 8, 2016

I'm not quite sure why trait expressions are generative (i.e., more like classes than objects). There is no initialization code, so no need to generate a fresh trait object. I see the main distinctions between traits and objects in terms of what traits are missing:

  1. default methods
  2. defs and vars
  3. initialization code.

@kjx
Copy link
Contributor Author

kjx commented Mar 8, 2016

I see the main distinctions between traits and objects in terms of what traits are missing:

  1. default methods
  2. defs and vars
  3. initialization code.

yes, that's right. and we can say that either way

I'm not quite sure why trait expressions are generative (i.e., more like classes than objects).

three reasons for me:

  • traits need take type parameters. This is very very hard to explain if they're not generative
  • traits can capture lexical bindings, which is hard to explain if they're not generative
  • I've been (and still are) trying hard to simply and regularise(sic) the rules on inheritance (and everything, basically). Traits have to combine with classes: fewer simpler rules are better if they'll do what is necessary

@KimBruce
Copy link
Contributor

KimBruce commented Mar 8, 2016

OK, let's give it a try that way.

@apblack
Copy link
Contributor

apblack commented Mar 8, 2016

I'm never sure what @kjx means when he says "generative". Object constructors are "generative" in the sense that they make a new object every time they are executed. That object can capture the lexical bindings that applied at the time of its creation. So a type variable used within the trait object might take on different values each time the trait object constructor is executed.

But I think that you want something more than that for traits. As you say, you want them to be parameterizable. That's why, I thought, you wanted the trait syntax to correspond to a method that creates a trait object. That's two levels of generation!

What about type definitions? Type definitions with parameters? Are they "generative"? In what sense?

@kjx
Copy link
Contributor Author

kjx commented Mar 8, 2016

@KimBruce - phew! good!

@apblack generative = makes a 'new' object each time, for suitable def of new object (especially where values are concerned)

Type definitions with parameters? Are they "generative"?

I think they have to be, in that the (conceptually) generate 'new' objects every time.
but (I hope) they generate value objects, and I'd like to get a version of Equality worked out where programs cannot tell if the reified types are the same or different objects. #91

@kjx kjx added the 1:now label Mar 8, 2016
@kjx
Copy link
Contributor Author

kjx commented Mar 8, 2016

 method traitExportingPrivateState { 
    var state' := 0 
    return object { 
      method state { state' }
      method state:=(x) { state' := x } 
    }
 }

@kjx
Copy link
Contributor Author

kjx commented Mar 8, 2016

  • trait shortcut should permit non-type parameters because the irregularity isn't worth the benefit.

@apblack apblack closed this as completed Mar 8, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants