Live CEOing Ep 793: Design Review of ExternalObject Features

Stephen Wolfram leads a design review of ExternalObject features in Wolfram Language, debating whether external sessions should return symbolic ExternalObject wrappers or auto-converted types, and proposing a new ExternalOperation form to safely compose operations before sending them to external systems.
Chapters
Okay. Hello everyone. Welcome to another design review. I'm as we head towards the next version of Wolfram language, this design review is about external objects and. Ricardo, take it away.
Hi.
Yeah, I think we already did one of these live stream on this topic. So today we are going to finalize the design. So we started writing the documentation and we are only writing the documentation for external objects. So we are adding all kind of did it inside the section, but I wanted to do like a brief recap of what we have done so far. So basically you start an external session and you get back a value. Like for example, here we are trying to work with dates. When you do that, external evaluate converts them to a data object. But from now on, basically you can specify that the return type is going to be an external object. So you can force the result to always be an external object.
So even if, just so I understand, in, in the usual external evaluate, I can also, instead of using that association, I can simply say, if I'm not mistaken, I think you have that example just right down below. STR arrow. Yeah, go ahead.
Yeah, so yeah, this is function application and so this is something that you cannot do in previous versions because it doesn't work.
I thought we had a mechanism for returning in particular format. Doesn't external evaluate have a blah arrow? Blah. You know, something like Python arrow?
Yes, that, but that, that, that will be on the session level. So on the session level you decided to start your session and all the type is going to be always a string, always an external object.
Why can't I also say external evaluative session arrow and then the return type that I want for that particular external evaluate.
That could be implemented.
Can we look at the documentation first and I'll evaluate for a second?
Sure. So if I.
Why are we doing that? Why don't you just look at it in the product? Well, look at it in the product.
I don't think I have it here. External evaluate, you said it's the same page.
Okay, so could you scroll up to the top? Yeah, that, that fifth usage sys arrow type right now, right. You're not specifying, you're not saying their session arrow type, but you could.
I. I don't think it's implemented this way.
No, I understand, I understand, I understand. I'm just saying that that would be consistent. Okay.
Yeah, it could be done, right? Yeah, I think we can do an action item for that. Yes.
Okay. All right. Okay, but now what you're giving.
But then on the message level, on the message level. So you can specify the return type in the association. And so now you can force it to return an external object, even if it was something else. External object is returned by default. When we don't know what to do with the. We divide an object and so you get back an external object. In this case, this is a date, so you get back a date. Object you get.
Now, so I understand the things we were discussing recently about external extension or. No, I'm sorry, extension object.
That's different, Stephen.
It's a different level.
Yes, it's a different level.
Okay, all right, so that would be, that would be what would wrap the result of the external evaluate afterwards. Okay, I got it. Right, okay, onward.
And then you can simply take the object and apply to a function by using this syntax. Or you can.
Wait, wait, wait, wait, wait, wait. The STR is the function, is that right?
STR is a function that is built in, in Python and basically works on every object and it returns the string of that. So it's a global thing.
Why is that the right notation for this for function application here? And why is it that way around, not the other way around? I mean, isn't it.
Basically here you can pass multiple arguments. In this case we are passing only one.
Yeah, I understand that, but. But why is it. What's our precedent for a function being applied being name a function arrow, whatever. I mean, like in an API call, for example, that will be a parameter name would have a. So I'm saying I, I just, I'm not sure what.
I. I know there is a bit of inconsistence here because basically the arrow on the left hand side is for the return type and on. And here in the message, the arrow is for function obligation.
Well, so hold on, so let's think about that for a second because I have a question. If. I mean, so you're going to define the return type. So one thing, I mean, you know, the other possibility will be the arguments arrow the function.
So this, this is not something that we are inventing yet. This is something that exists since version 12. So like.
I'm sorry, what exists since version 12?
This, this notation, that's what we use.
All the time, Stephen. So that's already like baked in design.
Where is it in the external evaluate documentation? I'm not seeing it.
Well here, no, but.
Well, so where is it? I mean, so. No, no, you can't. You're not allowed to just look at examples. You're not allowed to look at examples. That's not what.
Where is it?
Is it in the Documentation of specific languages or what?
Yeah, it's not specific to the parent name.
Did we goof. Do we have a piece of functionality we just didn't document?
I think so, yeah.
I can't remember where documented or if it's documented.
Well, so wait a minute, there's a specific page for Python, isn't there, for example?
There is, there is.
Let's look at that page. Could we please use the actual built in documentation? Go to the help menu and just use the help.
I. I don't have a build with documentation, unfortunately I can go on the web, but this is deep. Yeah.
Okay. Could you scroll to the top, please? I mean, Where is this document at all?
Yeah, I. I'm pretty sure there are examples, but yeah, probably that doesn't count.
That doesn't count.
Message specification, obviously.
Yeah.
I mean there is also the fact that this message thing must be documented somewhere because there are all kind. Okay, yeah, here.
Sure. That's document.
Document. The shortcut. Yes. Because basically this is. This is shortcut for.
Does that work in all languages? Does that work for all languages?
Oh, yeah, yeah. This is a framework level. Yeah. Functionality.
I mean, initially I didn't know it existed either and I was always using external function until it was pointed out to me that that's the syntax that's supported. And now using. Now I'm using that, but I agree that it should be documented.
So wait a minute. Well, how does the external function version of that work?
Well then it. Then it's. You don't have Arrow now. Then it just uses.
Then it's just standard Wolfram language function application.
Yes, yes, exactly. Yes. I mean the full form of this is basically similar to this one.
Yeah, I get it, I get it. With arguments, I understand, but with arguments.
Then.
I mean, external function is a little bit more standard in the, in the Wolfram language sense, I think.
So just write out what you would write there. With external function.
With.
With external function. Is this, is this example earlier.
Stephen means in one.
Hold on a sec. Hold on, hold on, hold on. So external evaluate. I see. I got it, I got it, I got it, I got it, I got it. So that's a shorthand but for external function within an external evaluate call.
Yeah, not only. I mean this, this is doing two backend call and this is doing one backend call, but this is. I mean it's functionally equivalent. This is faster because it does less round trip here you need to create the function and then apply it. Any edits to end function.
I'm kind of Annoyed that this isn't in documentation because I think it also was never design reviewed. I don't think it's the best designs. What else could we have, could we do as an alternative way to.
With the arrow? Well, the most obvious thing to do is to do the return type because basically it's on the left hand side and so we do.
No, no, no, no. I mean, what, what alternative for this thing that we want.
I think you should look at the function comp ref page for something similar. Right, yeah, let's look at input arguments, arrow and then the output argument. So go to. Yeah, Function compile. And then look at examples that. Yeah, look at examples. Let's see here. Yeah, where it says compiled code function in one of these examples as output.
Right?
Yeah, you got that signature thing there, right, the signature where it says integer. Yeah, a list of things. Right. That's the input, the argument types, arrow and then the result type. Now I don't know if in Python that there's an equivalent, but you know, that's the nearest thing that I can think of.
Yeah, that is because on the right hand side you have the return type. Here you don't have to return a type because you don't.
I mean, typeless.
Yeah.
All right, look, I, I don't think it's great, but let me just think for a second. What other operator could we use other than an arrow? It's kind of the only thing we have there, I think.
I mean, we cannot write it as a standard function, obviously.
No, we cannot.
Okay.
Well, I guess we have to use this. Okay, fine. Let's make sure it gets documented.
And I quite like the syntax. I think I understand what it does. The thing is that the string can be quite long, so you cannot just, you know, sort of use the string as a head or something like.
No, I know, well, but if it is code here and it's a single, then it can be as long as you want. So you do code, you will do blah, blah, blah.
Yeah, but, but people also write big long strings and that sort of thing.
Yeah, that's fine. Okay, right. All right, let's move on.
Yeah, the thing that is new is that. So basically, yeah, you can send it back and forth and yeah, the. It's basically equivalent of running this in Python. Now once you have the object.
Wait a second, wait a second. External evaluate has always been able to do that. That last line there, that's always impossible, right?
Yeah.
The difference is the data is getting converted correctly and that you're able to pass Data, basically.
I mean, the thing is, yes, you can write always Python code, but you know, if the input of your function is a giant numeric array, obviously you don't want to write that.
Yeah.
And so you, yeah, you can send data, you can send external object. And also, like this allow you to basically, yes. Have something that is big on the other side without bringing it back.
Okay, so let me just. If I said so, this thing could be like a giant matrix function. In that function there, if I define the return type to be external object, then when I say func of now, I would get back an external object.
Yes.
Okay, all right, fine.
Yeah, because you can also apply it in this way. Specify yes argument here and. And yes, and have back an external object. Okay. Now in terms of operation that you can do on the object itself. So like once you have the object, what can I do with it? So the design was basically influenced by data structure and the way you do operation. Data structure. And we have seen that. Yes, okay, yeah, and we've seen that. First of all, they are called operation there. And so we are calling it operation, not property here. And the way you extract other information is by using information. Now this is not something that I have implemented yet, but it's something that I was planning to implement where basically you do information on external object and you get back system available operations and so it will tell you, you know, that you can do all this stuff.
Well, it'll just be a list of the names, right? Okay, yep.
And whether the object is still active. And we were thinking that this could go under information and not be in an operation because it's kind of different. Meaning that an operation is actually doing something on the back end.
I agree.
Checking the result.
I agree.
Okay.
So can we look at these? So that call thing, it's not obvious. It should be varogs. Is there a precedent for making it varogs as opposed to a list of arguments?
Right. So inside data structure, there are no var thing here. Most of the things are vargs.
I'm sorry, there are varg things or they're not that.
There are not. There are not, no.
Okay, so why aren't those OGs in a list?
Well, they could. They will force you to add the list.
But I don't. I think we should have that.
But wait, isn't there a. If you had a list as the argument. Right.
No, it always would have a list.
No, but I mean if the argument was going to be a list to this function.
No, I'm saying even the one Argument case, it would involve a list, right?
But then you'd have to have like two early.
I don't even know why this thing exists. That first thing there is the equivalent of just saying, why isn't that. Oh my gosh, what a mess.
Let me finish, do the demo and then we move here. So redundant type is basically, you know, you have your object and then you ask for a certain redundant type. So, so basically this transform the object into either string or an expression. So in this case, the object was a date. So I'm asking for the expression and it gets me back, the expression.
I totally don't understand. I totally don't understand. This is a. No, I totally don't understand. This is a horrible hack. Look, you've got the external object, okay, and you're saying now I want to change its return type to the specified thing, right? And get a result. Correct, correct. Because now, in and of itself, if you just type now here, it will be an external object, right? So what you're trying to do, external object, is you're saying, I want to cast that external object into something else. I want to do a type conversion to something else. Right?
Right.
And this looks like it is asking for a return type. It's not saying cast this thing into that return type. I have an idea here, possibly, let's see how it plays out. I. I have an idea of essentially nested sub values that might be more reasonable. Because I just don't think this is right. I think this is asking, you know, in other words, if it is return, it certainly shouldn't say return type. If it says anything, it should be the operation is return, and then.
We have the operation evaluate, and they could be matched together. But the thing is, you want to evaluate and yes, return the expression most of the time. But you also might want to see what's the string representation on the other side. Because, you know, as soon as you.
Of course, yeah, I get it, I get it. But what is the difference between. I don't understand. Why is it called return? Return type is something you see in an association that states the type of the return. This is an operation that you're doing. You told me it's an operation. You named these things.
It is an operation. Yes, it is an operation. Basically.
Return type is a. Is a key of some kind. You see what I'm saying?
I think the confusion comes from the fact that we now evaluate is defined as shorthand with return type, as in an association. So it is a bit confusing.
Yes, this is wrong. I'm Sorry, it's just wrong. Okay. Return type is a fine key to put in the association. It is not the right operation. The operation at best is return if it's anything.
Well, okay, well, if.
Or evaluate.
Yeah, yes, it could be evaluate and.
Then it could be evaluating arrow string, for example.
Arrow string.
Because then it's consistent with the other ways we're using things like this.
What about like a function name like external cast, where you say external cast of the external object and then give the type that you want it to be.
That's a possibility too.
Can we test that out by typing.
That external convert or something? Right.
But we have avoided using those sort of top level outer wrapper functions for this because we have a whole bunch of operations and it should be an operation. They're different from language to language and so we've just sort of got this.
Are they. I mean, if they're not different, like the concept of an external object or an external function is, you know, I mean, to me I, I could imagine an external convert outer wrapper that will be useful for. Because. Okay, let's be clear. The case that this is relevant is for external objects. It's not relevant for anything else. It's casting external objects. It's not casting anything else. Am I correct?
Yeah, yeah, but, but it is technically internally this is just an operation for us because basically this is taking the object and applying string to it.
I, I understand. What do you mean applying string? It's not applying the fact that, you know that some kind of python operation is not relevant, that it, it's, it's doing a conversion.
We should, we should look at the ref page for cast. I think that that's an, close.
I mean the, the full form would be something like now evaluate comma, return type, arrow string. Yeah, well, that would be cons, but that is a bit unwieldy.
So maybe let's start off with what's right. Okay. Because this isn't right. Okay. Putting return type there as an operation is just totally wrong. Right. So personally I like the shorthand of evaluate arrow string.
I don't get that at all. I don't get the.
What does evaluate do? What does evaluate do? Show me what evaluate does. Okay. I don't understand why it does that. In other words, this, it is doing.
That because by default, so, so, so the, the object is bound to, to an external object. Right, but by default we know how to auto convert this object back. And, and, and by default.
Okay, but that's not really an evaluation operation because you Know, conceptually, an external object lives in the external address space of the.
It is an external evaluation when we, when we put it together with all the rest of the design, where those operations can be lazy. And so when you're asking to materialize it so to do the evaluate, even if it is just a representation of a string, you, if you were doing multiple operation on this object, one after the other, you are doing an evaluation. And even the fact that you are transforming this thing into a string is doing an evaluation on the other side.
I know, I think it's wrong. I think this is the wrong way to think about it. Okay, first of all, let's understand the bigger picture. The bigger picture is you have a bunch of operations here that are essentially doing things on the external side. Correct. So can. Can show me the table? Could you move the notebook that you have right now over to the left slightly? Okay, now let's look at the, the operations that you're listing here. Here's this. Okay, so, Okay, chain the operations. Oh my God.
But we went through all this stuff, Stephen, with you, why you are acting surprised. But again, when last time. So there is what. So get attribute is basically, you know, the equivalent. If you have an object that is now and now was up to this thing, you do get attribute of year and basically you are doing the same thing here. Method call is calling a method. So if the object was containing up to now and you're doing, how did.
You get the state passed me last time?
Well, you know, Stephen, the compose was something we hashed out as a win in a long session, improving over other designs on this sort of lazy composition of a bunch of method calls, you know, avoiding. We were pretty happy that the compose thing as a way to succinctly describe a series of operations in. In a row.
Right. I remember that somewhat. So can we go back again? I'm sorry. Okay, look, the return type thing is. It's just the wrong name for that.
This is one of the things that probably can be improved. Yes.
Okay, so returned, evaluate, return. Just return might be better. Okay, but let's.
But one thing that can happen is that if the object is unknown to us, so it's like some random Python object, you are getting back the external object. Now when you are doing this operation of return or evaluate without specifying, you know, that you want a string, you are getting back again the external object.
So I understand in this case you're getting the date. It's an attempted cast, and the cast might not work. Right. That's what you're saying, you're saying to cast it into this type, but it might not be possible.
Yeah, right, so return could. Yeah.
Okay, can we look in more detail at these things? Okay, so first point is the call version of this. Why isn't that just achieved by wrapping external function around the external object and then calling it?
You can do that as well.
Okay, can you show me that? Can you just type that in, please? Just say it's just external function of. Just external function.
Okay.
Type external function of the external object, wherever that is on line four. Okay, whatever. No, no, no, no. Now, now that should be an operator form of external function applied to arguments. Right, right, right.
That is. Thing would work because now it's. But I can put something else in here. I can put an actual function.
No, no, no, that's not what I'm asking for. I'm saying that rather than having this hacky backwards verag's call thing to just have external function. Okay, so that worked well. Wait a second. I don't understand why.
I'm using external function to. Basically. So this is part of the things that we can document or. But basically what I'm doing is that external function wrapped around an external object turns it into a function.
That's great.
And then you.
Yeah, that's exactly what we.
Right, you can do.
Well, so let's not document that call thing. Let's just do it that way.
Okay.
I mean.
Okay, let me just go on to.
Understand these other things. Okay, so method call. What's the difference between a call and a method call?
So this is basically just shortcut for, at least in Python, get attribute of something and then calling it. So this is just a shortcut.
Method call is different. Call is kind of a weird thing when the object itself can be seen as a function that operates on arguments method calls. Where I've got the more typical case, I've got an object and I want to call one of its named methods.
Right.
Okay, so I've got a suggestion then. Got a suggestion. Why not have that be. No, no, scroll back up again, please. Scroll back up again. I think that what is really nice is being able to use external function to use our function calling mechanism. Right. And what you're doing there, rather than putting it in some backwards, you know, tail of the sub value animal. Right. Have it be the case that you make something which is an external function that then you can apply to arguments just like you can any other function. See what I'm saying? So what I would suggest is in that line, external Function of wrapper, whatever it is, have the possibility external function of external object. Arrow the method name. Do you see what I'm saying? Maybe I should take and type this.
Yes, yes, no, I understand, I understand. So basically, if this is now and it has an object called a method.
A method called date.
Date, yeah. Yes. Then you can call it like that.
Right, so now what does the get attribute thing do? Get attribute.
Get gets an attribute. So basically, so it's equivalent of doing that in Python. So the underlying object is now, now get several attributes.
What's the difference in a method attribute? What's the difference between method and attribute?
A method is an attribute that is a function in Python, at least.
Stephen, in like C or something, these would be. A field is the expression we use in Java. C field, you know, you know, obj.year is a field.
Yeah, right.
Obj year with parentheses is a method.
Okay, okay, so let's think about how to do this.
Because date, for example, is a date, sorry, is a method. And so up to here it's, it's basically. Yeah, this is the method and then you call it.
Okay, okay, okay, I understand. So let's go back to assume that everything we want to call is wrapped as a function and the attributes.
Are.
And then, I mean, wouldn't it be nice if you could just use the sub value to get the X to get. No, no, you've got a setter there. No, you've got a thing called get attribute. That's a frigging setter. What the heck is that?
Sorry, no, this is a typo.
Okay, okay, I just don't buy this at all. I'm sorry. Look, look, look, why isn't. I mean, wouldn't it be nice if external object sub atter got the value of that attribute?
You're, you're converging on J link syntax here, Steven.
We, yes, we have been there. And, and then you cannot, but then you cannot do any kind of other operation because the, the, the, the beauty about this stuff, this, this is more like. You need to see this as a more low level, on top of which.
You build more, you know, why is it low? I mean, but if I've got an external object and I want to know properties of that external object.
Yes, you need to. The problem is that yes, you want to do several operation on this object. There is not getting an attribute is one of those operations. And yes, obviously we started with a design where basically you just. The first value in the sub value is an attribute. But then how do you call It. How do you do all these other operations?
How do you call. No, no, no, calling is wrong. You don't want to call it this way. You don't want to call it this way. You want to call it by wrapping external function around it.
Correct. But then, but then these. Getting this attribute would not, would not return to you the value. Right? Because it cannot return the value. Because now if, if this attribute is like the number two or three or a date or something that we understand now, you get back a value, not an external object anymore. And so when you do that, it cannot really reserve a value. So, so now you.
So what do you mean it can't return a value? You're saying certain attributes which are going to be these method calls should be returning an external function, should they not?
Some, some attribute. Yes, but now there are other attributes.
Like.
I don't know. Let's assume that you know. Yeah, there is, that there is a, There is something here that returns a date. Yes, now you get back a date object in Wolfram language, but assume you wanted to use additional. You wanted to do other stuff over this date in Python before returning it in Wolfram language. How do you do that?
Well, why don't you type the Python code then? I don't understand. Why are you doing what you want to. Okay, basically what you have invented here is a new thing that we could call external operation. Because what you're doing is you're saying there's external evaluate, which takes arbitrary code in the external language and evaluates it. Now what you're doing is, given that we now have external objects, we now have a new concept of an external operation done on those external objects, not in our evaluator. Right? You see what I'm saying? So just, just type out the word external operation.
Yep.
Okay, Because I think that's what we're going to want. Because if, if you had an external operation, then. Let's just think about that. No, I wouldn't do it that way. I would say external operation of. Oh, I see. The problem is that you need to know in the external operation get attribute. That's not enough because it's a. Unless. Unless it's kind of lazy up to the point where it knows what the object is. Do you understand what I'm saying? Because right now, otherwise, if that's a C get attribute, you sort of want a different thing than if it's a Python get attribute and you don't know which it is until you hit the object. You see what I'm saying?
I mean, Obviously you know that, that a certain object is coming from a certain evaluation system.
We don't understand that once you have the object. But at the level of. I mean, so, so if the external operation of get attribute is just a symbolic thing that means nothing until it's actually applied to an object, then that's okay. Let's just look at what it would look like if you had this external operation thing.
But I mean, in general the external object as an object wouldn't need any weapon because it knows, it knows methods and so you can use the object as the head and apply methods directly. You don't need to wrap it in anything.
But Stephen, also like, you know this thing that you are. This assumption that you're doing where basically the external object you call it with sub values and is going to be an attribute which is probably the most obvious thing to do is not really generic in every language. So, for example, SQL, right?
Yep.
Yeah. In SQL there is no attribute. Probably, probably it can be named as you know, if you have a query, it's just a column. I don't know. Obviously you will need to invent what it means there. But for example, in the plan that we were. I mean we have not been doing anything for external object and SQL yet. But one thing that you can do is that the external object is like the cursor and it got specific method in order to, you know, fetch some line out of the cursor like tanning. So this kind of method are to the evaluator. And they are. And, and it's a design basically allows you to do. Yeah. All kinds of stuff on every evaluator because every evaluator can have his own.
I. I understand. That's exactly why. So that's why I was yakking about the fact that the external operation here just has a name that doesn't. You don't know what it means until you've qualified it with the system you're dealing with.
Right.
That.
That is. Yeah, that is correct.
But that's what I'm saying. So. But I'm asking, is it conceivable. Okay, let's just run with the external operation for a second. Okay. Because. Okay, first point is I'm pretty sure this call. Let's just write down the. The call thing becomes external function of the external object applied to the arguments. Right. Okay, so let me.
So you, you were saying the call. What. What would be the call? So yeah. Ex. Okay.
External function.
Function of the object.
Of external object. Yeah, of arguments. Okay, very nice. I think that's very clean. Okay, next, the method call is external function of object, arrow method, name of arguments.
Okay, sorry, that is rule abuse. But anyway.
What do you mean? Why is it rule abuse?
Well, I mean, why an arrow? Because it's got arrows all over the place.
I know, but it's kind of.
I mean, it's looks like. It looks like C syntax, right? O, B J arrow method.
Also, remember that external function takes right now two arguments, which is the session and the function code.
Yes, but if you have an object, you don't have the session because you know which session it comes from.
Yes. Right. So this is a. This is a way of using external function as a way to transform an external object into a functionally appliable thing.
Right.
Okay, let's now look at attribute. Okay, what it means. So we got getting and setting attributes of an external object. Okay, so I'd like to propose that external object. And let's see if this works. It may not work. Okay, that external object can take a string, get. Get rid of all of that. Just say it's a obj of atta quotes attribute that that gives the attribute. And then obj of atta equals blah, blah, blah. As a setter, you could.
This is Jlic.
Okay, well, good merging on that. You invented this 25 years ago.
Right? Except Jlig doesn't use strings for these things. It uses symbols. But we have to use strings in general. We have to use.
Yeah.
Internally we went through this design. I'm telling you, internally we went through all these.
Honestly, as the developer of J Link, I think that this style of syntax, although it's beautiful and works great in J Link, I don't think it works in general for arbitrary languages because they're. So let me think. There's a whole bunch of reasons for this, but for one thing, J link implements this equals two thing with some hack to allow it to work, which would be nice to avoid.
Okay, but here it's a pure up value. It'll work with an up value, won't it?
Only because in J link, objects are symbols, they format.
The kicker.
I mean, there is a way to make it work with mutators. I've done it for external. For persistent symbols, it can be done.
Okay, so let's just go on here, because, you know, to me. Okay, so now we've got all this composition, this external chaining of operations. Okay, We've also got the cast operation. Let's talk about the cast operation, okay? That is basically taking the external object and is trying to return it in a particular form, right?
The way it, it could be gold cast.
No, no, no, no, no, no, no. Forget that. We're not. Forget that, forget that, forget that. What would be the right way to do it? What is, what is really going on? We've got an external object and isn't external evaluate. Doesn't external evaluate have the apparatus to do cost?
External evaluate is like if you, if you pass the object to external evaluate. Like, like for example, in this case where I have now it materialized the object.
Okay, all right, so fine, but.
So sorry, now was assigned to something else. That's, that's my bad.
But, but my question is this, okay, if, if you just. Okay, so you've got session now. Okay, fine, but why not just say external evaluate of external object and the syntax that you're using.
Oh, this also works, right? This also works like if you have a function. So if you have this function rep, you can use it here as well and it works. And repreh is an external function, so you can do a function application.
If you use existing syntax, it would be external evaluate of object comma, return, type, arrow, expression.
That works as well. Like yeah, if you put the full thing here and you do command goes.
To rep. No, that's not what we want. Let's go back, let's go back again. Let's go back again. You want a nice clean way to be able to take the external object and cast it. The external object which is not autocast itself for some reason, right? It has not been autocasted to orphan language type, but you now want to explicitly cast it. Am I, am I making sense? Right? Why would that ever work? Why would that ever be useful?
This is converting the object now in string.
I know, I know. Okay, but why is that? Okay, so you are saying that it is an external object which is really living in the external memory space. But I'm going to cast it. What could I cast it to? I mean, most costs won't work. If I say cast this to a, a number, for example, it won't work.
No, there are, there are few return types that you have in every, in every system and they are typically are something like just string, expression and external object. This is true for Python rabi node JS.
Okay, okay, okay, okay.
So let's.
In SQL is different like in SQL is row column.
Okay, let's look at what this would look like then. Because I don't think this is the right mechanism. I just don't think it's the right mechanism. I mean the, the Return type would be an external evaluate. Go. Go down to the bottom. Again, go down to the bottom where we were actually constructing things we want to have. Right. So we've got an object there. And if you say external evaluate of the object. External evaluate of obj, just type it in.
Okay. Yeah.
So that presumably by default would turn that object into an expression. Am I right? Correct. And that would already work. Is that true?
That will already work. Unfortunately, there is the operator form of external evaluate. And I can make it work as well. Despite the.
I think. I think you should do that. Despite. In other words, when that thing is.
We can object undocument. Yes. Or we can undocument the. The operator form, because we were thinking about this thing as well, and probably we can get rid of the over form in order to do that.
And so why do we want to get rid of the operator form? The operator form allows you to. No, I. I don't think we should get rid of the operator form.
Okay, well, okay, but external evaluate. It's weird that an operator form is, you know, evaluating in one case and not in the other. That's.
I know. So we have to think about it. Okay, we have to think about it. So let's just write the operator form. External evaluate of session of quotes, whatever it is. So. So let's just write a real version. External evaluate of a real version from nothing. Just copy that line. Copy the line. Copy this line. Copy the whole line. Copy the whole line.
Yep.
And replace. Just copy that line. Replace session with Python quotes. Python, sure. Does it. Evaluate it evaluated. Okay. I think that's a nice piece of functionality. So I don't think we want to give that up.
Right.
Okay, so what we need is the cast operation.
For the external object.
Yes.
Yeah. And unless you want to create a new function, this is already possible to do by doing this where commas.
No, but the command is a big can of worm. I mean, that's nasty. Okay, but there is the other syntax that you already have, which is to say external evaluate. Just repper arrow. No, no, repper arrow string. Right. Or now arrow string.
That is. That is function application. That is function application. Not for now.
Yeah, that's. Well, session arrow string, comma, now is return type. Try it. External evaluative. Session arrow string comma now of session arrow arrow, string.
Oh, no, this doesn't work right now.
But it could work. Comma, comma, it could work. Okay, all right. Okay, so that should work.
Yeah.
Okay. All right. Okay, so.
All right, but this, I mean, string is not head Nut has nothing to do with session, right?
No, it's the return value. It's. It's the same thing as we're doing elsewhere, where we give the return value. You know, it's the same thing we have, don't we? Python arrow strings.
Right, so this, so this is. Yes, this is already working and this is a.
Right, so I think that's. Yeah, okay, so let's just, let's go.
Yeah, but the main, the main problem is that if now is an external object, then how would you know what session it came from? You don't need to know because the object knows, so we need something that doesn't.
Oh, I know, I know, I know, I know, I know, I know.
Now we could, we could go back to something like making it of now comma, return or now comma evaluate.
I mean, this inside the. Evaluate.
No, inside the object. Now.
Now is an object. Obj.
Yes, yes, indeed.
And now we have to decide what does obj do we. Oh, God, this is a mess. Those things where you say obj of Atta OBJ is quite nice. It will be nice to keep that so we don't muddy up the attribute thing and muddy up the setter as well. Okay, but now we also have this cast operation. Right? That's the. Okay, what. What are the other operations we're trying to handle? We've got.
Yeah, I mean, or could we just have.
Okay, we've got.
No, I mean, I mean, I mean the, the only operation that we really need are get attribute and call and method call. Those are the three things that.
Okay, but fine. Everything proposing to do is make the attribute be a sub value and make the call be achieved with external function.
Yes, but what about sharing operation, all this stuff? We don't.
What about. No, no, no, I know, we're about to talk about that. We're about to talk about that, but.
I mean it simply.
Wait, wait, wait. We've got another operation which is the cast operation. Okay? You want to be able to take the external object and somehow forcibly cast it. Now I have to say that what that really is is external function. Am I not correct? Type it in, please. External function. And what's the Python command to turn things into strings?
Str.
Okay, but. But you need to say Python at the beginning there.
Right, right, right.
Or session or something. Python comma str. And now apply that to now.
Okay, I need. They need to be in the same session.
But yes, try it. Yeah, that works fine, fine. So, yeah, but wait, wait, wait, wait, wait, wait, wait, wait, wait. Wait, I know. You don't need that session there because it's already contained in the object. Right, that's what you're going to say. So we need a way to apply.
Functions to the object.
Yes, functions that. To the object, knowing what session they're in. Right.
Which don't be done. General functions be function or something. I mean, there could be an operation there that is function application, where the first argument is a function and gets applied.
But can we use the return type as the method? So we can say obj of expression, obj of string. I mean, that's how Python does it anyway, right?
So it's obj, you're saying instead of the attribute, say obj, type it obj.
Square bracket, expression, or even this. Even the symbol expression of it.
Right?
Or the string.
No, no, no, no, no, no. Just that. Just the. The express that. No, no, no, no, not.
Yes, that's what I meant.
Okay, but I meant something different. So that's one possibility. The other possibility is obj of expression. Not the string expression, but expression. Do you understand? Get rid of the quotes, okay? Which is unambiguous with that attribute thing. In other words, what's that same for.
String and external object, which are the three possible return types.
Yes. So I mean, a string could be the attribute, and there are other. It's a little weird, but it's not totally weird. But I mean, the main point to realize is that that string is the only thing you can put in there to represent an attribute, right? So any other structure can represent another operation done on the external object. Do you see what I'm saying?
So we would have objf expression or string or external object.
Well, I mean, one thing that you can do also is to pass a function here, and it will. You don't really need. Because you would call the function without bj, but.
Yeah, well, why would we need that? Because that's just an inside.
It's only not to specify a session. But I guess you need to do it in any case.
Wait, wait. The external function doesn't need to specify the session, does it?
Not when it's created by us, but when it's created by you.
No, no, I don't understand. I don't understand. Explain to me that case. Okay, yeah.
So external function takes two arguments, like external evaluate. The first argument is the session. The second argument is the code. The actual. The actual.
All right, but what we've said, what we've said here is that external function wrapped around an external object will return an external function in the appropriate session.
Yes, yes, yes, that is already working. External function, external object.
Yes, I think your statement is correct as long as external function is applied to external object. But if external function is applied to something from the Wolfram language side, then it's not correct, because then you would have no way to extract the session from those.
That's correct, that's correct. Unless. Unless what's returned is an external object, which then can contain the session information.
No, because you will need to apply the function first, and if you don't know what the session is, you can have no return type at all.
No, no, give me the example.
Okay, let's say you have external function that just sums 1 and 2 and returns 3. Okay, how do you know which session it belongs to? If you just feed it one and.
Two when you applied that, you know the, the. The three is in Wolfram language address space, not in the external address space. So it's irrelevant where it is. It's not.
Type it out, Type it out.
You'll see.
Stephen, if you type external function plus as a string and then try to apply that to 2 and 3, where does this going? Just type external function, forget the Python, leave that out for now and type plus and then as art, and give it the arguments 1 and 2.
I know that can't work.
That's what.
But that's what I'm saying, that couldn't work. So what?
So, yes, but, but I mean, it works. My point is that in this particular case, you will need to specify the session.
Which case? Which case are we talking about?
This one that Ricardo has just written.
Down here doesn't specify a session.
Well, implicitly it does, because when you say Python, it creates a session, then.
It removes the session. Now, where's the place where we have to keep the session persistent?
Let's say you have a function that you return from Python side, for example. It basically picks the value of some.
I don't care what it does, it's returned. If it's returned from the Python side, it's returned as an external function.
Yes, yeah, that's a good point. So, but my point, My point rather was that in general, external function should have some information about the session. Where it is tied to.
Well, it depends. Yes, of course it should have. When would it not have? I'm completely confused. When would it not have?
Well, what you started with, you suggested that external function, when it is applied to external object, it doesn't have to know which session it belongs to because.
The external object knows. So external object knows. Yeah, Right, right.
And my point has been that we cannot in general consider external function without a reference to the, to the session where it is defined.
All right, Stephen, your example, you were saying just now, external function applied to an object. Well, the object has a session, but.
Right, so.
But what if it's not applied to an object?
I'm sorry, what?
What if it's not applied to an object?
What's the example? What's the example?
Take, delete the word Python from what?
Then it won't work. Then it won't work.
That's what we're saying. That's all we're saying.
And it won't work. But why would we want that to work?
We don't want it.
Okay, so what are we talking about?
I thought that you would.
Stephen, I can explain why, because like, long before external Violet even existed, I faced this problem with R link. And in fact, if you look at our link documentation, I define references to functions of two kinds. One is the kind that always exists because you define it essentially by a string of code and then you don't need to know because you can reconstruct this function for a given session. But there is another one which incorporates certain state from the evaluation session.
I understand, right, I understand that, but in either case, I mean the generic with just a quotes Python there, that's a generic, which is a pop up session in that case. But it could also be incorporated into another session. You see what I'm saying?
Yeah. So if you have this convention that generic will, will basically imply default session.
Yeah. Then that probably default session absorbed into whatever session it needs to be used in.
But we are still only trying to solve the problem of converting external objects into expressions.
No, I'm not. No, no, no, that problem. No, no, no, no, I'm. No, that problem. What I'm suggesting is a sub value, a string. Sub value means an attribute. We define three special attributes, expression, string and external object.
Yes.
Those attributes are supported whenever they can be because expression might not work.
Yes, so we are in agreement. I mean that was my suggestion about 10 minutes ago, but.
Right, okay, so I agree with that. Okay, so.
Okay, good.
Let's, let's look at the, the composition question. Okay. Because that's the one thing we haven't.
Discussed here, I mean that, that there is also the fact about what other operation, like for example in py, other than get attribute, the most obvious operation that you want to do is get item, which is kind of similar, but, but not identical. Like you know, get attribute is object dot attribute and Then there is object. Sorry, and then item here, which. Where item is a string as well, like attribute. And this is how you extract stuff from a dictionary. Dictionary is like association. And so we. We also have. Obviously I'm not documenting yet because it's not for every language, but get item is kind of important, for example, in Python. And it's like. I wouldn't say that is as. As useful as get attribute, but depending on what kind of object you're interacting with, it might be that this is a quite common operation. And this is why we were having this thing where basically, you know, there are possibly different operation that you want to do with sub values that is not just accessing the attribute. And again, we went there, we tried to. Did that design didn't work out and we never even discussed it with you. But.
Yeah, right, but.
But Ricardo, within what still suggests right now all the other things will probably go under some external operation thing.
I understand, I understand that. Well, I don't know.
I mean that. That is one possibility external operation of. And then we can have endless named external operations.
Yes.
For each language. I mean, this is the question, do we want to tail these things and sub values with great messiness in many cases, even if we have special cases for external function of external about object, you know, we could, I suppose, have, I mean, I don't know how many different kinds of attributings and items and extractions and sub casings. How many? Which language? It's like. No, not much, but my favorite is, you know, is the language which has like 35 cases. You know, is there. Is there a situation where we'd have. Okay. I mean, we can't predict how many wacky different sub casings people use. I mean, it's like we have part extraction and we have function application and they're different. Right, right.
But if we think in terms of sub values, I think the first and most important answer question we have to answer is whether we will introduce some unwanted premature evaluation on the Wolfram language side that we may later want to control. Because that would be bad.
Well, that's what you're proposing here. And all of these things you're proposing, you know, all of these are immediate evaluation. Right, all of those things you're suggesting. Get attribute, et cetera, et cetera.
Yes, all of this, they got immediate evaluation unless you use basically compose delayed and which compose delayed. You are putting all this stuff.
What's that?
Why? I'm not sure.
It's horrifying. Okay, okay.
Why it's horrifying not sure, because it's.
Just like hack upon hack upon hack. You know, it's this thing.
I mean, compose compose and compose delayed are just, are the difference between set and set delayed over the object. So compose does the set and compose delay. That's set delayed. And those are like kind of low level thing that you need to do, you know, because the thing is we are solving the, you know, what people want to do interactively, which is, you know, get the value right here and right now.
Let me make a suggestion.
You need to make a suggestion in front of it.
Let me make a suggestion. I think it's an easy solution here. Okay, let's imagine that. Go, go back down to that object attribute thing. Okay, Go back down to the bottom. Back down all the way to the bottom. Okay, so here's my proposal. Okay, the generic cases object of a string means the attribute. Could you type this please? Obj of quotes atta. No, no, no, no, no, whatever. OBJ of quotes atta. No lowercase A. Well, it doesn't matter. Okay, okay, now that's the generic case. Now the next case is obj of. OBJ of Open brace. Open brace, open brace.
Okay, like list.
Yes, list. Okay, Quotes get item and then whatever the hell you want, the item name or whatever. Okay, so that, the idea is that the generic is attribute, but if you give that list or possibly you can do it with a rule instead, then you get a different thing. You see what I'm saying?
Then what's the semantics of this obesity one? What will it mean?
It means do the get item thing. Means the same thing you had over.
There on the right, except method call too. Is this how we do method call as well?
I don't think it should work this way for method call most of the time. I think method call is mostly done with external function. External. Look, look for a method call. If it's a method, you're telling me the attribute which is the method name that OBJ of atta returns an external function, doesn't it? And then you can just apply it.
Well, sure, you're doing two operation to the backend instead of one, but. But yeah, so it's twice as low.
But yeah, I mean, let me explain a little bit. The rationale behind all that design on the right. The idea that Ricardo had and then sort of agreed with that was that at the end we have some intermediate inert representation of a chain of operations like an ast, but in Wolfram language. And then the backend can decide in more complicated cases when people Want to chain things whether you want immediate evaluations in the chain, or whether you want chain and execute everything on the other side. So we needed that intermediate representation. And so exactly how syntactically, on top of that, we built all this nice syntax is probably of no concern to us. But if that syntax will require premature evaluations of parts, that can be a concern for us. I'm not sure if I expressed it clearly.
Oh, yeah, you expressed it. It's a big hack, Tower. I mean, I understand the stuff that you want to evaluate only in the external system.
Maybe.
That should be done using External Evaluate, which right now its second argument is just a string. Maybe you need it to be something more complicated. If you want it to be evaluated in the external session, then put it inside External Evaluate because that tells you make it be evaluated externally. So that, I think, is a possibility to have something in the second argument. There's. That is effectively a. I mean, I don't know how rich that second argument is right now, but that will be the place to put all these composed crazinesses, because that's what it's telling you to do. Externally evaluate this thing.
Yeah.
Okay, look, here's a. Here's an issue, okay? We've got a pig here in terms of. Of, you know, these external languages with all their crazinesses. And the question is, can we dress it up so that it looks like, you know, a sleek city dwelling, you know, whatever it is. Right. And maybe it's not possible. Maybe in the end, you know, the trotters of the pig are going to stick out and we're not going to be able to hide all that stuff. You know, what we're trying to do, perhaps incorrectly, is to put a business suit on the pig. In a sense, maybe that analogy just fell flat.
Yeah. But I mean, there certainly is a good argument in favor of having a syntax that is more familiar to Wolfram language users.
So I guess it could be that I really like the way External Function works, external object, and so on. I think they're very clean and I think that they're things where, you know, and I think Arnaud, who's been using this stuff a bunch, maybe he can speak to how he feels about those things.
Yeah, I mean, I like the way things are working right now. I didn't really have a big objection to the design that's on the right there, because I think it's, you know, sort of a low level design. Right. That. That only a few people are going to be using.
This is not well, okay, but if that's really the case. But if it's. If, if instead it's going to be true that, you know, a lot of the code that you're writing on Node, for example, is going to have, you know, get attributes of this thing, blah, blah, blah.
You know, I don't think that's the case, but I'm. I'm not sure. I just haven't started using it yet, so I can't really comment on, you know, which one.
Well, okay, look, over and over. Compromised position would be that we introduce external operation and put. What I'm worried about is burning up what is potentially nice syntax with sub values for external object on all the stuff, which I consider to be incredibly messy. You see what I'm saying? I mean, some of it is uncontroversial about what happens when you say external function of external object. But I understand that you want to be able to put things together. So what would happen if we just used external operation for all these things. And you have. Your composed thing basically becomes external.
But so you are. Okay, so there are a few possibilities. Like, okay, one thing is that external operation is purely symbolic of thing. And you know, I don't know, I'm making this up. Object and then you boot get item and then you boot all your stuff. Right? And then in order to evaluate this guy, you pass it to external evaluate. And so the full thing is going to be external evaluate of session comma. Yeah, this thing.
That's a safe way to do this.
And then you don't need the, the delayed call, you don't need the compose call because in the end you are in control. I mean, Right.
And by the way, when you add external evaluates could drop the session. In that case it wouldn't need the session because that's part of the object.
That's part of the object. Yeah. And the other thing is that maybe external operation is not about the object, it's just an operation that you write it. You know, you're gonna have an option and then. And then. Yes, you do. OBJ goes to external. I. I don't know, but, but yeah, inside.
Okay, is the name external operation. Right. I again, I don't necessarily want to use that up for something that is kind of a. I mean, let's think.
About external language operation.
No, because we're not using that elsewhere.
I mean, for sure there are, there is a whole bunch of things that we can document in any case by just using properly. As you were saying, you know, external function. And also the Ability that you can pass external object back and forth.
Okay, but let's look, this is. But the operations allow expensive design which we can then decide to have shortcut syntaxes that use the sub value of external object later on if this is the full form.
And so you're saying that basically for we. We don't do anything for subvalue for now and we only do external operation and then we decide what to do with sub values later.
Okay, yes, that's what I'm suggesting. So let's think about this. Is external operation the right term regarding this, Steven?
I think if external operation remains always a purely symbolic thing, even better, maybe an operator form that if it's completely inert, then using it here would not necessarily restrict its use in other parts of the language. Should we later want that?
Well, so wait a minute. The operator form to get the OBJ out of there and then have the obj be subvalue of external operation.
Something like that. It wouldn't even necessarily have to be a sub value because I mean syntactically a sub value. But. Yeah, but not evaluating at all because it will be externally valid, which will understand what this is.
Yeah, I understand.
I mean this is the actual internal thing that I'm using where basically it's. I'm calling it remote procedure call.
I. I don't care. Let's not look at.
No, but, but just, just to. Well, basically the operation is at the beginning and then. And then it's called.
That's nice.
Just like Wolfram language, you know, it's the same idea more or less, only for external languages. But. But yeah, this is more or less what it is. But I guess we don't want.
Okay, so why don't we just type in external operation? Just type external operation. Just type on separate line external operation of whatever. You know, get item, call whatever you want to make it be.
Let's not use get item, let's use method call. That's by far the most common operation you're going to want to perform is calling a method call.
We have an alternative way of doing method call.
We. I'm not sure we do have an alternative.
Yes, we did. We just went through.
Doesn't solve the problem of specifying the return type. The casted return type, for example.
What the hell is this? No, this is wrong. What is this? What the heck is that? No, absolutely not. External operation just. It has one operation method call, right? Get all the other junk out of there and.
And, and what? Okay, and then now if you want.
To return A special type. You say arrow something or other if you want. Want in that. In that place in the external operation. Okay, now the external operation is a method call and it can be applied to an external object. So type quotes obj there. I mean, not quotes of obj. Of obj. Okay, now. No. What. What the heck's the other thing? That. What is that other. What is that name thing? Why is there a name?
Name is the name of the method and 2 and 3 are the argument to the method itself.
Okay, get that into the external operation. Then that goes in the. Okay, so get rid of the arrow.
Which is why I was writing like this.
Okay? But don't put the external object there. The external object to which it's being applied is a sub value.
Okay, so like this.
Right? Right. Okay. I. I really think that that should be in a list. The external operation stuff inside there should be in a list.
So that from here.
No, no, no, no, no, no. The whole thing. The whole thing in a list. The whole thing.
The whole thing.
The whole thing in a list. So that if you want to chain it with multiple operations, you can do that by giving. No, no, no, no. There's no second list there right now. Right, get rid of the second list. Okay, now that thing would do absolutely nothing unless it's put inside external evaluate.
Okay, so. Okay, so the whole thing, even when you call it with sub values.
Well, you tell me.
Yeah, I mean, it depends.
Like you tell me. I mean, maybe there's a way to do that. I. I would think it either, you know, what's it. What's it going to do? I. I mean, I. You're telling me that it's so important that it. Well, actually, if.
Well, look, if. So.
No, if you can chain it there, then the external operation becomes a chained thing. What are you doing?
No, I'm just saying that in the end, when you're writing this for real in actual code, you know, it's going to be probably OP1 is going to be inside a variable. And. And so. Yeah, I mean, I. I don't know. I'm just.
Well, okay, so look, maybe it's external operation. Maybe you can chain the external operation there as you wish to chain them by having a, you know, veros of the external operation. So I'm. I'm nervous about that. I would prefer multiple sub lists. Let's assume it's multiple sub lists. External operation, multiple sub lists.
But why, why, why you. You wouldn't want to do it?
Because I'm nervous that you're going to need another thing like a session information in certain cases.
Okay, no, I, I, I, I think here the, a good design will be that this thing is doing only this thing and, and any kind of other meta information is going somewhere else.
I think I'm, I'm going to tell you I think it would be safer to have it be sub. But anyway, it doesn't matter.
But if external operation is, is able to have multiple operations for training, then you really don't need the external evaluate around it because you just do the thing.
I agree.
Right, so external operation, this line, external operation of blah blah comma OBJ would do what the evaluation would do the evaluation. It has all the information it needs.
Right.
And we can chain it by having multiple lists in the external operation.
Why can't you chain it by doing actual.
An alternative, which is what I was doing in the previous design, was to have this thing be lazy first. And so doing this will accumulate, will return a new external object that didn't do anything. And then you need to feed the external object to external evaluate in order to resolve it. And so basically if OBJ is an external object, doing this thing is doing some manipulation only on the expression level of the external object without doing anything on the evaluator and then you feed it back to external evaluate in order to, and this was one of my first design, but this kind of design was basically, you know, people were thinking that is not really good for, you know, programmatic interactive users. Sorry, right.
There was, there was a very clear reason. I mean, if, if you want, Stephen, I can explain why that design was something we frowned upon.
But I don't know when you're speaking about something like this, and we are not sure whether it should evaluate or not. Like this operation could interior an external lazy object, let's call it like that or otherwise.
I think with external operation, Ricardo, we have no problems of that anymore because it basically takes care of everything you wanted to do inside lazy external object, doesn't it?
Yeah, more or less, yes. It's just that you need to keep keeping track of this external operation by yourself if you cannot accumulate inside the object.
Hold on, hold on, hold on, hold on, hold on. Why can't you put, why can't you compose external operations explicitly compose them like you want to run three things together. You literally say external operation of blah of external operation, blah, blah, blah.
Okay, if they are not doing anything like, if they are not really evaluating, you can safely do that because in the end it's going to be a working language operation. And, and it's. Nothing is going to go wrong. In the previous design, the thing is extracting an attribute and then doing a method call and then doing another things. The second operation might fail would result in a failure. And now you are passing a failure to the next thing and now you got a splotch. And so like as long as the operation are completely lazy. Yes, you can do that if the operation are.
But what you could do if you wanted to, if you use the scheme of accumulating the sequence of operations into an external operation. Okay. Then the composition of external operations could. An explicit composition could turn into a single external operation that has strung together the operations inside it. Does that make sense?
I was going to suggest that in fact.
So the idea is that if you write F of G, then it would do it step by step with round trips. But if you say composition of F comma g of obj.
Well, no, no, I'm suggesting that if you write. Oh yeah, yeah. Right. But if you write. Yes. If you write the composition, the composition would evaluate to a composed external operation. Right. You're suggesting that, that. Well, I don't think it's exactly that. I think it's.
Yeah, it's. Stephen, it's just a statement, you know, composition is flat. You're suggesting something similar to the composition being flat.
Yes, that's what I'm suggesting.
Right.
I think this is looking promising. I can't claim to have thought through all the. I'm just very nervous about using the sub value of external object in this as I see it, rather hacky way. And, and by the time we've got all these delayed compose and so on, I think we're, we're kind of. That's, that's a self answering question that we're not doing the right thing.
Right. But with this external operation, if it stays completely inert, I think it probably will solve all the problems we wanted to solve with those.
I think it stays inert until it's applied to an object. Right.
The vents. Yeah, I mean, yeah, sure, yeah.
Right.
Like this thing, like really is like some lower level thing. I mean.
Yeah, that's enough.
Expecting people, but expecting people to write this every time they want to access an attribute or doing a function call. I mean. Yes, you are saying that.
I'm sorry, that's what we get. Look, listen, I think there's a nice syntax for that stuff, but we're not ready for it. We're just going to get it wrong. So I'm saying if you want to do the, the you know, nifty way to access an attribute. Then we've got to invent a proper syntax for it. We just tried. We just concluded that there are seven different things you want to do. The syntax that you have proposed is very ugly and I think will fall over. Okay. And this is. This is a more defensive design that. Yes. Involves more typing. Am I making sense? And I. I'm saying the external object, if you want to, you know, compose together seven things in the external operation, you can do that right now with substrings. Am I making sense?
Okay, yeah, well, I guess you mean.
Several arguments inside external operation.
Yeah, I mean several different operations.
Yes. External operation of list one, comma, list two, comma, list three.
Yeah, yeah, that's what I'm saying.
And composition of external operations would turn into that. Composed into that.
Yes.
Then have form do a single trip to the remote.
Yes, that's correct. When you apply it to the object, nothing happens until you apply it to the object. When you apply it to the object. Just like external function doesn't do anything until external function just sits there until you apply it to the. To. To something. Right, right.
And in fact, Roman, I think at some point you suggested something similar to external operation. During our design.
That's quite possible.
But so, so we came sort of back to this. But now Stephen suggested that.
But yeah, I mean, the big difference is, I mean, at some point we decided we didn't want anything around the object. Right. Because that would mean that we would need to know things about the object outside of it. And now we are still.
Yeah.
And in fact, let me make this comment, Stephen. In fact, the way we build this queries now with external operation is very similar to the way we build entity queries for databases by combining inert things, you know, so basically there are cases where it might be advantages. This is my point.
Yeah. As you know, I don't like those. You know, I prefer. I think what we should do with databases is always return something, which is what you were saying you tried earlier, to always return an external object.
Right.
Why doesn't that work for databases? No, for this case, why doesn't it work to do an operation and always return an external object?
This is, this is what, what, what my original design was. And the object was lazy, actually. And then you need to resolve the object.
Yeah, right. The reason why at least I dislike that design was that to me, external object is something that points to something existing in the other workspace. And if you have two types of external objects, some materialized and some to be materialized. And maybe they will never be materialized. Maybe there'll be a failure. To me, that was something rather confusing because I would prefer external object to be something where I can count that, okay, there is some actual object on the other language side corresponding to this external object.
Well, but not always. Like, you know, you. One. One time you want to do that.
I have to.
And this is set.
Sorry, the.
The.
Yeah.
And then, then there are other cases where you want that every time you evaluate the object is now. And so it's always dynamic. Right.
Listen, let me just make a meta comment here, okay. We tried to stand up this design involving more and more ornate sub values. It is falling over of its own weight. We need an alternative. I am not thrilled about. I mean, I'm. I guess so long as external operation is purely something that works by sub values, It. It's probably okay. It's probably okay. It's a little bit hard to explain why an external operation is different from an external function, except that it's a built in operation. You see what I'm saying? Right? Yeah, yeah, right.
But still, most people who would actually want to use external operation will not be very regular users who want interactive things because we probably will have simpler syntax for interactive use.
Yeah, I agree. So, I mean, I think this is probably right. Think it through, see what we've missed and. Okay, I'm sorry, I'm really late for something else, so I'm okay. All right. The, the functionality here is very nice. So I'm not, you know, there's nothing just, you know, this is what happens with these designs. You, you go in a certain direction, you build the tower and sometimes the tower falls over. And that's kind of what I see this as having happened. In this case, I think delayed compose is my final. The final thing that's pulling on the tower. Anyway. My point of view. I don't know. Roman, Todd, do you want to make any.
But see, you don't mind. You don't mind if internally we still convert everything into, into this style that's documented here, right? You just care about what you.
I don't care. I care about what the users see.
It's a little bit like data structures, right? I mean the way data structures, the interface, the API for data structures is not at all the way we would use it in Wolfram language. But it is very convenient. It is very convenient as a glue code into the compiled world. And if you don't want, you don't see it.
But if I can, why the reason why we did that is because there is a similarity between. Between this thing and data structure. They are most. They are both some mutable thing. I know, that you interact with by. By doing. Yeah.
Yes, but data structures is more limited. I mean, they. They don't have five, three or four different things you can do to them.
Well, they have particular operations, but they don't have these deeper, you know.
Yeah.
Kinds of things. Why don't we. Okay. See whether the thing we've designed here works. I'm optimistic that it will. I'm not guaranteeing that it will.
No, we.
Right.
We will discuss it internally. And then. And then we get back.
We're going to probably need one more. Maybe, if we're lucky. If you think it works, then it's going to be a fairly short next meeting. If you think it doesn't work. You know, I think our plan B is some slightly more defensive design version of what you proposed. Deeply experimental, because I don't think it's going to survive. And so that means it has to be more defensive so that when we change it later, we can still maintain compatibility. All right, thanks, guys. See you later. Okay, thanks.
More from Guy

Cheryl Strauss Einhorn | The Human Edge: Smarter Decisions in the Age of AI | Talks at Google

Rachel Glennerster | Innovation and the Center for Global Development | Talks at Google

Rebecca Winthrop | Rethinking the Purpose of Education in the Age of AI | Talks at Google

Dr. Robert Wachter | A Giant Leap: How AI Is Transforming Healthcare... | Talks at Google






