Not sure what's covered or not here, but a use case that I think is important is this:
Being able to have multiple objects with the same interface and then being able to pass any one of those into a method and that method can use any of them via the object pointer.
For example, I might have a serial driver, and LCD driver, and a network driver, all of which have these functions: SendChar, SendString, & SendNumber. Then I can have a method, say DumpInfo, that calls SendChar, SendString, & SendNumber on whichever of the objects I happen to pass in.
So I could do DumpInfo(@SerialDriver) and DumpInfo(@LCDDriver) and DumpInfo(@NetworkDriver) and they would all work.
If we can do that, then great! If not, then I am sad. I can already do this in C/C++, but it would be great if it was in Spin2.
Not sure what's covered or not here, but a use case that I think is important is this:
Being able to have multiple objects with the same interface and then being able to pass any one of those into a method and that method can use any of them via the object pointer.
For example, I might have a serial driver, and LCD driver, and a network driver, all of which have these functions: SendChar, SendString, & SendNumber. Then I can have a method, say DumpInfo, that calls SendChar, SendString, & SendNumber on whichever of the objects I happen to pass in.
So I could do DumpInfo(@SerialDriver) and DumpInfo(@LCDDriver) and DumpInfo(@NetworkDriver) and they would all work.
If we can do that, then great! If not, then I am sad. I can already do this in C/C++, but it would be great if it was in Spin2.
We can do what you want, with additional indexing for both the object and the method, both represented by the pointer. I don't know what would be more flexible than that.
Yes, we can do stuff like that. Methods can return multiple values, too. They could feed multiple assignments, as in your example, or they could feed multiple parameters within other methods.
Small thing... you mentioned that functions can return multiple values. Does that mean we can do a multiple assignment like this?
x, y := 10, 20
This would be useful for swapping two variables, something frequently done in Python.
x, y = y, x
Jon,
Curious as to where its frequently used in python. I’ve been programming in python almost full time for more than 6 months and i don’t recall the need. What am i missing?
Being able to have multiple objects with the same interface and then being able to pass any one of those into a method and that method can use any of them via the object pointer.
For example, I might have a serial driver, and LCD driver, and a network driver, all of which have these functions: SendChar, SendString, & SendNumber. Then I can have a method, say DumpInfo, that calls SendChar, SendString, & SendNumber on whichever of the objects I happen to pass in.
So I could do DumpInfo(@SerialDriver) and DumpInfo(@LCDDriver) and DumpInfo(@NetworkDriver) and they would all work.
The general idea is very desirable, but the devil is in the details. In C/C++ what you're looking for is accomplished by having types and inheritance. How would inheritance work in Spin? What syntax would we use? Would there be virtual functions? (It seems as though in Chip's interpreter all functions are virtual in a sense).
The ideal case would be to have some form of "duck typing" where no explicit inheritance was required and the compiler would automatically insert some plumbing behind the scenes to make things work as long as the appropriate methods are present on the objects passed in. But again, the devil is in the details. What happens if the methods are declared in different orders in the different objects? What if there are other methods interspersed?
I *think* I could make something like this happen in fastspin, by having the compiler construct a virtual object with pointers to the methods that need calling. That is, given a method:
PUB DumpInfo(OBJ outputter)
outputter.SendString(string("value of x is:"))
outputter.SendNumber(x)
outputter.SendChar(13)
The compiler would figure out that the "outputter" object parameter needs to have methods SendString, SendNumber, and SendChar (in that order). Then in a call like:
DumpInfo(@serial)
it would construct a 4 long shim containing a pointer to the VAR area of the "serial" object, and 3 function pointers (to the SendString, SendNumber, and SendChar methods of the serial object), and pass a pointer to that as the parameter to DumpInfo. The function pointers are needed because we don't know in what order those methods are declared in the original objects: you might have a serial object for which SendChar is method #1, SendString is method #2, and SendNumber is method #3, but a network object that declares SendString first (method #1), SendNumber as method #4, and SendString as method #7.
In Chip's Spin2 interpreter the "function pointer" might just be the appropriate index into the method table; in fastspin it would be the address of the method.
Could openspin do something like this too? I haven't looked at the openspin internals.
All of this gets more complicated if the OBJ parameters can themselves be passed to sub-functions; it means the analysis of what methods are needed has to be recursive. I think it's probably do-able, but a lot of work in the compiler. On the other hand it would be nice for the user for things to be this simple and to "just work".
Small thing... you mentioned that functions can return multiple values. Does that mean we can do a multiple assignment like this?
x, y := 10, 20
This would be useful for swapping two variables, something frequently done in Python.
x, y = y, x
Jon,
Curious as to where its frequently used in python. I’ve been programming in python almost full time for more than 6 months and i don’t recall the need. What am i missing?
While I don't have any opinion on whether this should be added to Spin, I want to point out the more general mechanism that Python is using here. In the above code snippet, you are temporarily creating a tuple on the right-hand side, then unpacking it back into the original variables on the left-hand side. So, in the same way, this also works:
x, y, z = y, z, x
or more explicitly:
x, y, z = (y, z, x)
Okay. Maybe I do have an opinion. If syntax like above were to be added, then I'd rather it be in support of a more generalized tuple/list mechanism than just syntax sugar for
Curious as to where its frequently used in python. I’ve been programming in python almost full time for more than 6 months and i don’t recall the need. What am i missing?
Probably nothing -- I was merely sharing my own experience. Yes, it's "sugar" -- but isn't that part of the Python sales pitch?
While I don't have any opinion on whether this should be added to Spin, I want to point out the more general mechanism that Python is using here. In the above code snippet, you are temporarily creating a tuple on the right-hand side, then unpacking it back into the original variables on the left-hand side. So, in the same way, this also works:
x, y, z = y, z, x
or more explicitly:
x, y, z = (y, z, x)
I can't speak for Chip, but that is an example of the kind of thing that he had talked about in the Spin discussion threads and it's the way I've implemented multiple assignment in fastspin (evaluate N values on the right, then assign them to N variables on the left). It's also possible to do things like:
x, y := rotxy(x, y, t)
where "rotxy" is a function that's defined to return two values.
I have to program in a couple of languages, and I never liked the definition of return values as parameters. Say out xxx in C# or by reference in general C calling convention.
Having a defined RETURN value at the end of some method makes reading code way more easy.
While I don't have any opinion on whether this should be added to Spin, I want to point out the more general mechanism that Python is using here. In the above code snippet, you are temporarily creating a tuple on the right-hand side, then unpacking it back into the original variables on the left-hand side. So, in the same way, this also works:
x, y, z = y, z, x
or more explicitly:
x, y, z = (y, z, x)
I can't speak for Chip, but that is an example of the kind of thing that he had talked about in the Spin discussion threads and it's the way I've implemented multiple assignment in fastspin (evaluate N values on the right, then assign them to N variables on the left). It's also possible to do things like:
x, y := rotxy(x, y, t)
where "rotxy" is a function that's defined to return two values.
Can you use the multiple return values returned by a function directly as parameters in another function call? In other words, if I have a function foo() that returns two values and a function bar(a, b) that takes two parameters, can I write this statement?
bar(foo())
The intent being that the first return value of foo will be used as the "a" parameter of "bar" and the second return value of foo will be used as the "b" parameter of "bar".
where "rotxy" is a function that's defined to return two values.
Is there any chance of that type of thing trickling down into FlexBASIC?
Adding this to BASIC would be easy, if we can find an unambiguous way to parse it. The BASIC syntax is already a bit tangled, I'm afraid. Perhaps we could set aside some new characters like '[' to group things in assignments, so we'd write:
While I don't have any opinion on whether this should be added to Spin, I want to point out the more general mechanism that Python is using here. In the above code snippet, you are temporarily creating a tuple on the right-hand side, then unpacking it back into the original variables on the left-hand side. So, in the same way, this also works:
x, y, z = y, z, x
or more explicitly:
x, y, z = (y, z, x)
I can't speak for Chip, but that is an example of the kind of thing that he had talked about in the Spin discussion threads and it's the way I've implemented multiple assignment in fastspin (evaluate N values on the right, then assign them to N variables on the left). It's also possible to do things like:
x, y := rotxy(x, y, t)
where "rotxy" is a function that's defined to return two values.
Can you use the multiple return values returned by a function directly as parameters in another function call? In other words, if I have a function foo() that returns two values and a function bar(a, b) that takes two parameters, can I write this statement?
bar(foo())
The intent being that the first return value of foo will be used as the "a" parameter of "bar" and the second return value of foo will be used as the "b" parameter of "bar".
fastspin works that way, and my impression was that Chip's Spin2 would as well.
While I don't have any opinion on whether this should be added to Spin, I want to point out the more general mechanism that Python is using here. In the above code snippet, you are temporarily creating a tuple on the right-hand side, then unpacking it back into the original variables on the left-hand side. So, in the same way, this also works:
x, y, z = y, z, x
or more explicitly:
x, y, z = (y, z, x)
I can't speak for Chip, but that is an example of the kind of thing that he had talked about in the Spin discussion threads and it's the way I've implemented multiple assignment in fastspin (evaluate N values on the right, then assign them to N variables on the left). It's also possible to do things like:
x, y := rotxy(x, y, t)
where "rotxy" is a function that's defined to return two values.
Can you use the multiple return values returned by a function directly as parameters in another function call? In other words, if I have a function foo() that returns two values and a function bar(a, b) that takes two parameters, can I write this statement?
bar(foo())
The intent being that the first return value of foo will be used as the "a" parameter of "bar" and the second return value of foo will be used as the "b" parameter of "bar".
fastspin works that way, and my impression was that Chip's Spin2 would as well.
While I don't have any opinion on whether this should be added to Spin, I want to point out the more general mechanism that Python is using here. In the above code snippet, you are temporarily creating a tuple on the right-hand side, then unpacking it back into the original variables on the left-hand side. So, in the same way, this also works:
x, y, z = y, z, x
or more explicitly:
x, y, z = (y, z, x)
I can't speak for Chip, but that is an example of the kind of thing that he had talked about in the Spin discussion threads and it's the way I've implemented multiple assignment in fastspin (evaluate N values on the right, then assign them to N variables on the left). It's also possible to do things like:
x, y := rotxy(x, y, t)
where "rotxy" is a function that's defined to return two values.
Can you use the multiple return values returned by a function directly as parameters in another function call? In other words, if I have a function foo() that returns two values and a function bar(a, b) that takes two parameters, can I write this statement?
bar(foo())
The intent being that the first return value of foo will be used as the "a" parameter of "bar" and the second return value of foo will be used as the "b" parameter of "bar".
fastspin works that way, and my impression was that Chip's Spin2 would as well.
That's right. It would be nice if there was some innocuous way to signal in the method call how many return values are coming out of it. For method pointers, it will be necessary to specify, but for normal methods there's no need. It would be nice if there was some visibility, though. Maybe we could make a button, when clicked, shows the numbers of return values, without affecting the actual source code. Some kind of super view.
What happens if I call a function that returns two values but my statement only receives one? For example, if foo(x) returns two values, what happens with this statement? Is the second value just ignored?
What happens if I call a function that returns two values but my statement only receives one? For example, if foo(x) returns two values, what happens with this statement? Is the second value just ignored?
@eric supports optional parameters in spin2, with a given default constant value.
PUB whatever(a,b,c=1,d=2)
and it can be called as
whatever(1,2) -->whatever(1,2,1,2) ' the last two default value
whatever(1,2,3) -->whatever(1,2,3,2) ' the last one default value
whatever(1,2,3,4) as usual
Adding this to BASIC would be easy, if we can find an unambiguous way to parse it. The BASIC syntax is already a bit tangled, I'm afraid. Perhaps we could set aside some new characters like '[' to group things in assignments, so we'd write:
[x, y] = rotxy(x, y, t)
That would be ideal! So would the function itself would look like:
FUNCTION rotxy(x as long, y as long, t as long) as long, as long
dim f, g as long
f = (x + y) * t
g = (x - y) / t
return f, g
END FUNCTION
Sorry to hijack the thread, but this little addition would REALLY make my world a better place!
What happens if I call a function that returns two values but my statement only receives one? For example, if foo(x) returns two values, what happens with this statement? Is the second value just ignored?
a := foo(x)
In fastspin it just ignores the second value, but it sounds like Chip's interpreter gives an error, so it's probably best to match up the return values (I may change fastspin to match Chip's Spin2 for this).
Adding this to BASIC would be easy, if we can find an unambiguous way to parse it. The BASIC syntax is already a bit tangled, I'm afraid. Perhaps we could set aside some new characters like '[' to group things in assignments, so we'd write:
[x, y] = rotxy(x, y, t)
That would be ideal! So would the function itself would look like:
FUNCTION rotxy(x as long, y as long, t as long) as long, as long
dim f, g as long
f = (x + y) * t
g = (x - y) / t
return f, g
END FUNCTION
Sorry to hijack the thread, but this little addition would REALLY make my world a better place!
Probably more like
FUNCTION rotxy(x as long, y as long, t as long) as [long, long]
...
but I need to look into this. No promises yet, but it would be nice to upgrade BASIC to have this feature, it's one of the few things that it's missing as compared to Spin.
What happens if I call a function that returns two values but my statement only receives one? For example, if foo(x) returns two values, what happens with this statement? Is the second value just ignored?
a := foo(x)
In fastspin it just ignores the second value, but it sounds like Chip's interpreter gives an error, so it's probably best to match up the return values (I may change fastspin to match Chip's Spin2 for this).
It might be nice in some cases to be able to just ignore the second value. Say I write a function that divides one integer by another and returns both the quotient and the remainder. I might want just the quotient and it would be too bad to have to have two different functions for this. I guess that's not a very strong argument though.
What happens if I call a function that returns two values but my statement only receives one? For example, if foo(x) returns two values, what happens with this statement? Is the second value just ignored?
a := foo(x)
In fastspin it just ignores the second value, but it sounds like Chip's interpreter gives an error, so it's probably best to match up the return values (I may change fastspin to match Chip's Spin2 for this).
It might be nice in some cases to be able to just ignore the second value. Say I write a function that divides one integer by another and returns both the quotient and the remainder. I might want just the quotient and it would be too bad to have to have two different functions for this. I guess that's not a very strong argument though.
I think the Go language handles this by letting you write "_" for a value to be ignored, e.g.:
What happens if I call a function that returns two values but my statement only receives one? For example, if foo(x) returns two values, what happens with this statement? Is the second value just ignored?
a := foo(x)
In fastspin it just ignores the second value, but it sounds like Chip's interpreter gives an error, so it's probably best to match up the return values (I may change fastspin to match Chip's Spin2 for this).
It might be nice in some cases to be able to just ignore the second value. Say I write a function that divides one integer by another and returns both the quotient and the remainder. I might want just the quotient and it would be too bad to have to have two different functions for this. I guess that's not a very strong argument though.
I think the Go language handles this by letting you write "_" for a value to be ignored, e.g.:
q, _ := mydiv(a, b)
_, r := mydiv(a, b)
Perhaps Spin2 could adopt that?
That can be done just by convention rather than explicit support in the compiler as long as "_" is a valid symbol name.
What happens if I call a function that returns two values but my statement only receives one? For example, if foo(x) returns two values, what happens with this statement? Is the second value just ignored?
a := foo(x)
In fastspin it just ignores the second value, but it sounds like Chip's interpreter gives an error, so it's probably best to match up the return values (I may change fastspin to match Chip's Spin2 for this).
It might be nice in some cases to be able to just ignore the second value. Say I write a function that divides one integer by another and returns both the quotient and the remainder. I might want just the quotient and it would be too bad to have to have two different functions for this. I guess that's not a very strong argument though.
I think the Go language handles this by letting you write "_" for a value to be ignored, e.g.:
What happens if I call a function that returns two values but my statement only receives one? For example, if foo(x) returns two values, what happens with this statement? Is the second value just ignored?
a := foo(x)
In fastspin it just ignores the second value, but it sounds like Chip's interpreter gives an error, so it's probably best to match up the return values (I may change fastspin to match Chip's Spin2 for this).
It might be nice in some cases to be able to just ignore the second value. Say I write a function that divides one integer by another and returns both the quotient and the remainder. I might want just the quotient and it would be too bad to have to have two different functions for this. I guess that's not a very strong argument though.
I think the Go language handles this by letting you write "_" for a value to be ignored, e.g.:
q, _ := mydiv(a, b)
_, r := mydiv(a, b)
Perhaps Spin2 could adopt that?
Yes, that could be done.
Now that I think of it, a little compiler support would probably help. It would be useful if you didn't have to declared the "_" symbol and also if it it didn't take any space. That will probably happen as part of code optimization in FastSpin but might require explicit support in Chip's Spin2 if it doesn't optimize out dead code.
Comments
Being able to have multiple objects with the same interface and then being able to pass any one of those into a method and that method can use any of them via the object pointer.
For example, I might have a serial driver, and LCD driver, and a network driver, all of which have these functions: SendChar, SendString, & SendNumber. Then I can have a method, say DumpInfo, that calls SendChar, SendString, & SendNumber on whichever of the objects I happen to pass in.
So I could do DumpInfo(@SerialDriver) and DumpInfo(@LCDDriver) and DumpInfo(@NetworkDriver) and they would all work.
If we can do that, then great! If not, then I am sad. I can already do this in C/C++, but it would be great if it was in Spin2.
http://forums.parallax.com/discussion/166096/new-spin/p29
We can do what you want, with additional indexing for both the object and the method, both represented by the pointer. I don't know what would be more flexible than that.
Ah, thanks for finding that, Eric. I was wondering where it was. I will review it.
Curious as to where its frequently used in python. I’ve been programming in python almost full time for more than 6 months and i don’t recall the need. What am i missing?
The general idea is very desirable, but the devil is in the details. In C/C++ what you're looking for is accomplished by having types and inheritance. How would inheritance work in Spin? What syntax would we use? Would there be virtual functions? (It seems as though in Chip's interpreter all functions are virtual in a sense).
The ideal case would be to have some form of "duck typing" where no explicit inheritance was required and the compiler would automatically insert some plumbing behind the scenes to make things work as long as the appropriate methods are present on the objects passed in. But again, the devil is in the details. What happens if the methods are declared in different orders in the different objects? What if there are other methods interspersed?
I *think* I could make something like this happen in fastspin, by having the compiler construct a virtual object with pointers to the methods that need calling. That is, given a method: The compiler would figure out that the "outputter" object parameter needs to have methods SendString, SendNumber, and SendChar (in that order). Then in a call like: it would construct a 4 long shim containing a pointer to the VAR area of the "serial" object, and 3 function pointers (to the SendString, SendNumber, and SendChar methods of the serial object), and pass a pointer to that as the parameter to DumpInfo. The function pointers are needed because we don't know in what order those methods are declared in the original objects: you might have a serial object for which SendChar is method #1, SendString is method #2, and SendNumber is method #3, but a network object that declares SendString first (method #1), SendNumber as method #4, and SendString as method #7.
In Chip's Spin2 interpreter the "function pointer" might just be the appropriate index into the method table; in fastspin it would be the address of the method.
Could openspin do something like this too? I haven't looked at the openspin internals.
All of this gets more complicated if the OBJ parameters can themselves be passed to sub-functions; it means the analysis of what methods are needed has to be recursive. I think it's probably do-able, but a lot of work in the compiler. On the other hand it would be nice for the user for things to be this simple and to "just work".
While I don't have any opinion on whether this should be added to Spin, I want to point out the more general mechanism that Python is using here. In the above code snippet, you are temporarily creating a tuple on the right-hand side, then unpacking it back into the original variables on the left-hand side. So, in the same way, this also works:
or more explicitly:
Okay. Maybe I do have an opinion. If syntax like above were to be added, then I'd rather it be in support of a more generalized tuple/list mechanism than just syntax sugar for
I can't speak for Chip, but that is an example of the kind of thing that he had talked about in the Spin discussion threads and it's the way I've implemented multiple assignment in fastspin (evaluate N values on the right, then assign them to N variables on the left). It's also possible to do things like: where "rotxy" is a function that's defined to return two values.
I have to program in a couple of languages, and I never liked the definition of return values as parameters. Say out xxx in C# or by reference in general C calling convention.
Having a defined RETURN value at the end of some method makes reading code way more easy.
Mike
On the other end this allows interesting opportunities to 'group' data in a function and type less parameter.
Question would be how many parameter would be allowed, usable.
Mike
Adding this to BASIC would be easy, if we can find an unambiguous way to parse it. The BASIC syntax is already a bit tangled, I'm afraid. Perhaps we could set aside some new characters like '[' to group things in assignments, so we'd write:
fastspin works that way, and my impression was that Chip's Spin2 would as well.
That's right. It would be nice if there was some innocuous way to signal in the method call how many return values are coming out of it. For method pointers, it will be necessary to specify, but for normal methods there's no need. It would be nice if there was some visibility, though. Maybe we could make a button, when clicked, shows the numbers of return values, without affecting the actual source code. Some kind of super view.
You'd get a compiler error.
PUB whatever(a,b,c=1,d=2)
and it can be called as
whatever(1,2) -->whatever(1,2,1,2) ' the last two default value
whatever(1,2,3) -->whatever(1,2,3,2) ' the last one default value
whatever(1,2,3,4) as usual
very useful.
Mike
That would be ideal! So would the function itself would look like: Sorry to hijack the thread, but this little addition would REALLY make my world a better place!
In fastspin it just ignores the second value, but it sounds like Chip's interpreter gives an error, so it's probably best to match up the return values (I may change fastspin to match Chip's Spin2 for this).
Probably more like but I need to look into this. No promises yet, but it would be nice to upgrade BASIC to have this feature, it's one of the few things that it's missing as compared to Spin.
I think the Go language handles this by letting you write "_" for a value to be ignored, e.g.:
Perhaps Spin2 could adopt that?
Yes, that could be done.