Parameter defaults are awesome, but undocumented #808

Closed
davidhesselbom opened this Issue Aug 20, 2014 · 29 comments

Projects

None yet

4 participants

@davidhesselbom
Contributor

I can do

import lang/IO
aFunction: func (value := 2) { value toString() println() }
aFunction(1) // prints 1
aFunction() // prints 2

which is totally awesome, but not mentioned anywhere in the ooc documentation as far as I can tell. I was missing out until another guy tried it assuming it would just work, and it did :)

So then I tried to do

testClass: class {
    value: Int
    init: func (=value := 4)
}

Which didn't fly:

error Malformed function argument (remember, it's name: Type in ooc, not Type name)

Unless anyone thinks this is a terrible idea, I'll see if I can figure out how hard it would be to get this to work (maybe with a slightly different syntax, like init: func (=value = 4), dropping the :). I guess Nagaqueen.c is a good place to start?

@fasterthanlime
Collaborator

Well, (=value := 4) is kind of ugly :(

Thinking of other options: (.value := 4), or just (value = 4) (but it's not
obvious that it's a member)

I'm pretty sure @shamanas could get it done easily - and just for
reference, NagaQueen.c is generated using greg from the nagaqueen LEG
grammar, links:

https://github.com/fasterthanlime/greg
https://github.com/fasterthanlime/nagaqueen

That feature will probably require some changes in rock/middle/Argument.ooc
as well

Cheers,

  • A

On Wed, Aug 20, 2014 at 1:01 PM, davidhesselbom notifications@github.com
wrote:

I can do

import lang/IOaFunction: func (value := 2) { value toString() println() }aFunction(1) // prints 1aFunction() // prints 2

which is totally awesome, but not mentioned anywhere in the ooc
documentation as far as I can tell. I was missing out until another guy
tried it assuming it would just work, and it did :)

So then I tried to do

testClass: class {
value: Int
init: func (=value := 4)}

Which didn't fly:

error Malformed function argument (remember, it's name: Type in ooc, not Type
name)

Unless anyone thinks this is a terrible idea, I'll see if I can figure out
how hard it would be to get this to work. I guess Nagaqueen.c is a good
place to start?


Reply to this email directly or view it on GitHub
#808.

@davidhesselbom
Contributor

Agreed, it's not exactly pretty. Thanks for the info about NagaQueen, that C file also isn't exactly pretty ^^

@shamanas
Collaborator

Yeah, generated parsers tend to be that way :)
I think this would be pretty trivial to implement indeed but I'm not too fond of the syntax either

Perhaps

Foo: func {
    x: Int

    init: func (x =:= 4)
}
@shamanas
Collaborator

And of course

    init: func(.x := 4) { this x = x + 1 }

for (dot + default)-arg

@shamanas shamanas self-assigned this Aug 20, 2014
@fasterthanlime
Collaborator

for (dot + default)-arg

Isn't that what I suggested? :)

@shamanas
Collaborator

Ah the way you phrased it I thought you were suggesting .x := y as an alternative to =x := y and I just pointed out that the default dot-arg syntax is obvious and not that ugly as-is (if it were implemented).

Any thoughts on =:= ?

@fasterthanlime
Collaborator

=:= is a backward version of the famous "cat with a mustache" operator from
Perl 7. I don't like it

On Wed, Aug 20, 2014 at 2:46 PM, Alexandros Naskos <notifications@github.com

wrote:

Ah the way you phrased it I thought yo uwere suggesting .x := y as an
alternative to =x := y and I just pointed out that the default dot-arg
syntax is obvious and not that ugly.

Any thoughts on =:= ?


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

@davidhesselbom
Contributor

.x := y is similar to .x, but x =:= y is not very similar to =x compared to =x := y.

Anyway, .x := y, while not ugly, seems strange to me, since you're assigning a variable of a known type a value using the := operator from another known type. Or is y's type not known?

@shamanas
Collaborator

Yeah, I think you are right, .x = y should work, since the dot is just a way to get the type of the argument from the class field.

Actually there isn't much of a point in doing .x = y anyway, x := y should be the same thing if y is the same type as the class's x field.

@davidhesselbom
Contributor

Not unless you want to enforce that the parameter x is the same type as the class field. x := y does not enforce that. For assignment, like I wrote in the OP, the colon is also not needed, =x = y should work. But it's still ugly.

@shamanas
Collaborator

Yeah if y is a child class of x's class it would make sense to do .x = y indeed.
=x = y still seems quite awkward but I can't think of anything better :/

@davidhesselbom
Contributor

Amos suggested earlier to just do x = y, which should then fail to compile if x isn't the name of a class field (I think), since no type was specified. This would make things a little prettier, but it's not obvious to the uninitiated that this also assigns the class field x the value of y, and it's not clear whether x can be used later, i.e. whether

Foo: func {
    x: Int
    init: func(x = 4) { x toString() println() }
}

should be possible or not.

@fasterthanlime
Collaborator

Let's just give up and use func(4 =x)

On Wed, Aug 20, 2014 at 3:21 PM, davidhesselbom notifications@github.com
wrote:

Amos suggested earlier to just do x = y, which should then fail to
compile if x isn't the name of a class field (I think), since no type was
specified. This would make things a little prettier, but it's not obvious
to the uninitiated that this also assigns the class field x the value of y,
and it's not clear whether x can be used later, i.e. whether

Foo: func {
x
init: func(x = 4) { x toString() println() }}

should be possible or not.


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

@davidhesselbom
Contributor

Tempting. ;)

@fasterthanlime
Collaborator

or (=x ?? 34)

On Wed, Aug 20, 2014 at 3:23 PM, davidhesselbom notifications@github.com
wrote:

Tempting. ;)


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

@davidhesselbom
Contributor

Not actually that bad, if you're thinking about adding the ?? operator anyway!

@fasterthanlime
Collaborator

Yup, it kind of makes sense.. but not completely.

Someone might want to pass null as an argument and then the '??' operator
doesn't really make sense anymore.

And it's still to different from (x := 34)

On Wed, Aug 20, 2014 at 3:27 PM, davidhesselbom notifications@github.com
wrote:

Not actually that bad, if you're thinking about adding the ?? operator
anyway!


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

@davidhesselbom
Contributor

True.

@fasterthanlime
Collaborator

Hm.. then again.. the usecase for (=x := 2) is kind of limited.

For a class, one might have the default value directly in the member
declaration, right?

On Wed, Aug 20, 2014 at 3:44 PM, davidhesselbom notifications@github.com
wrote:

True.


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

@davidhesselbom
Contributor

... yes. I'm an idiot, I forgot all about that. The only time you'd have use for it is when you

  • have several init functions that take different parameters and
  • still want to have default values that are
    • different from in the member declaration and
    • specific to that init function and
  • don't want to have to write any code in the actual implementation of the function

... and I can think of convoluted situations involving inheritance where this might happen, but only if I try hard.

@davidhesselbom
Contributor

(.x = y) is still somewhat useful, though.

@fasterthanlime
Collaborator

It's true. There's still cases where it would be useful.

But even right now, it's easily worked around with the old-fashioned:

X: class {
a: Int

init: func (a := 42) {
this a = a
}
}

The problem with adding more and more features is that it's more work to
maintain, and ultimately, a more fragile compiler...

On Wed, Aug 20, 2014 at 3:59 PM, davidhesselbom notifications@github.com
wrote:

... yes. I'm an idiot, I forgot all about that. The only time you'd have
use for it is when you

  • have several init functions that take different parameters and
  • still want to have default parameters that are ** different from in
    the member declaration and ** specific to that init function and
  • don't want to have to write any code in the actual implementation of
    the function

... and I can think of convoluted situations involving inheritance where
this might happen, but only if I try hard.


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

@davidhesselbom
Contributor

Yes, this was about not having to do { this a = a } all along, which is no biggie, just... neater. Especially if you have many parameters. This was the point of having (=a) in the first place, right? :)

@fasterthanlime
Collaborator

Correct. After designing that way, though, I got to talk to other language
designers, and came to adopt a slightly different position.

There's basically two schools of thoughts at war here:

  • Those coming from a Java/C# world, who say an object should be almost
    fully initialized by an often long-and-complicated chain of constructors so
    that the object eventually ends up in a valid state.
  • Those coming from a more prototype-oriented / dynamic world (let's say
    JavaScript/Ruby/Lua/whatever) who say that an object should have at most 1
    constructor with at most 1 argument, and start in a fully valid state (even
    if not immediately useful) - and then you can mutate it to fit your needs.

Both approaches are valid and have uses, I'm just not too excited at the
idea of ending up with an even bigger syntax/semantic mess regarding
constructors in ooc. But oh well... I also had in mind something quite
simple for generics and see where that got us :)

On Wed, Aug 20, 2014 at 4:06 PM, davidhesselbom notifications@github.com
wrote:

Yes, this was about not having to do { this a = a } all along, which is
no biggie, just... neater. Especially if you have many parameters. This was
the point of having (=a) in the first place, right? :)


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

@davidhesselbom
Contributor

Mm. Well, I'm not a language constructor, but I don't like writing verbose code unless I have to, and ooc is generally remarkably succinct without being hard to read. I especially appreciate things like being able to put This in places where in C# I would have to spell out the entire class name. (.x = y) is just one of those cases where ooc could be even better, but as you say, it's at the cost of adding complexity to the compiler.

@vendethiel

Perl 7

Actually, that's an operator of Perl6: (no clue what Perl7 is ...)

$ perl6
> 1 =:= 1
True

(it's more for the compilers tho, see here: it just tests whether the LHS is bound to the same thing as the RHS)

@fasterthanlime
Collaborator

See! I knew it.

I said Perl 7 to poke fun at them, but it's even in Perl 6.

On Wed, Aug 20, 2014 at 5:31 PM, Nami-Doc notifications@github.com wrote:

Perl 7

Actually, that's an operator of Perl6: (no clue what Perl7 is ...)

$ perl6

1 =:= 1
True

(it's more for the compilers tho, see here
http://perlcabal.org/syn/S03.html#Comparison_semantics: it just tests
whether the LHS is bound to the same thing as the RHS)


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

@fasterthanlime
Collaborator

Original issue closed in ooc-lang/ooc-lang.org@8ee8033 — feature request is a separate thing.

@fasterthanlime
Collaborator

(Note: not deployed the website yet, but will do)

@fasterthanlime fasterthanlime modified the milestone: 0.9.10 Jul 10, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment