Uploaded image for project: 'OASIS Open Data Protocol (OData) TC'
  1. OASIS Open Data Protocol (OData) TC
  2. ODATA-239

Allowing expressions to be passed as parameters to (super) functions

    Details

    • Type: New Feature
    • Status: Closed
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: V4.0_WD01
    • Fix Version/s: V4.0_WD01
    • Component/s: ABNF, URL Conventions
    • Labels:
      None
    • Environment:

      [Applied]

    • Proposal:
      Hide

      Relax ABNF from

      functionExprParameter = functionParameterName EQ ( parameterValue / firstMemberExpr )

      to

      functionExprParameter = functionParameterName EQ ( parameterValue / commonExpr )

      Note: this passes in the result of the expression to the function (not the expression)

      Show
      Relax ABNF from functionExprParameter = functionParameterName EQ ( parameterValue / firstMemberExpr ) to functionExprParameter = functionParameterName EQ ( parameterValue / commonExpr ) Note: this passes in the result of the expression to the function (not the expression)
    • Resolution:
      Show
      Accepted: https://www.oasis-open.org/committees/download.php/49055/odata-meeting-35_on-20130502-minutes.html#odata-239

      Description

      To be able to use/extend the set of functions that can be used in a $apply query option functions need parameters of type expression, which expression can then be applied to each and every instance in the set they are processing.
      An very simple example of such a function would:

      $apply=GroupBy()/TopN(N=5, Value=Revenue)

      Where 5 is just a number indicating the top N we are interested in but were 'Revenue' is actually an expression referring to the Revenue property of the entity in the set the function is acting upon. A better example in which this becomes more apparent would be:

      $apply=GroupBy()/TopN(N=5, Value=Revenue sub Cost)

      For build in functions we can obviously simply define this but currently there is no way of defining a 'custom' function that could implement the same behavior because we can't pass in expressions.

      We then could annotate these functions to signal to tools that they can be used in $apply.

        Attachments

          Activity

          hubert.heijkers Hubert Heijkers (Inactive) created issue -
          ralfhandl Ralf Handl made changes -
          Field Original Value New Value
          Proposal Relax ABNF from

          functionExprParameter = functionParameterName EQ ( parameterValue / firstMemberExpr )

          to

          functionExprParameter = functionParameterName EQ ( parameterValue / commonExpr )
          Description To be able to use/extend the set of functions that can be used in a $apply query option functions need parameters of type (lambda) expression, which expression can then be applied to each and every instance in the set they are processing.
          An very simple example of such a function would:

          $apply=GroupBy()/TopN( 5, Revenue )

          Where 5 is just a number indicating the top N we are interested in but were 'Revenue' is actually an expression refering to the Revenue property of the entity in the set the function is acting upon. A better example in which this becomes more apparent would be:

          $apply=GroupBy()/TopN( 5, Revenue - Cost )

          For build in functions we can obviously simply define this but currently there is no way of defining a 'custom' function that could implement the same behavior because we can't pass in expressions.
          To be able to use/extend the set of functions that can be used in a $apply query option functions need parameters of type expression, which expression can then be applied to each and every instance in the set they are processing.
          An very simple example of such a function would:

          $apply=GroupBy()/TopN(N=5, Value=Revenue)

          Where 5 is just a number indicating the top N we are interested in but were 'Revenue' is actually an expression referring to the Revenue property of the entity in the set the function is acting upon. A better example in which this becomes more apparent would be:

          $apply=GroupBy()/TopN(N=5, Value=Revenue sub Cost)

          For build in functions we can obviously simply define this but currently there is no way of defining a 'custom' function that could implement the same behavior because we can't pass in expressions.

          We then could annotate these functions to signal to tools that they can be used in $apply.
          Environment [Proposed]
          Hide
          mikep Michael Pizzo (Inactive) added a comment -

          I don't think this works; this says that I can pass any arbitrary expression, but doesn't say how that expression is interpreted. Does this mean I can pass any expression to any function, or do we need to have a way to define that a function takes an expression?

          How would we differentiate between passing the value of the expression (as we do with firstMemberExpression today) and passing the expression itself? For example, how do I differentiate between passing the value for revenue versus the expression revenue?

          Show
          mikep Michael Pizzo (Inactive) added a comment - I don't think this works; this says that I can pass any arbitrary expression, but doesn't say how that expression is interpreted. Does this mean I can pass any expression to any function, or do we need to have a way to define that a function takes an expression? How would we differentiate between passing the value of the expression (as we do with firstMemberExpression today) and passing the expression itself? For example, how do I differentiate between passing the value for revenue versus the expression revenue?
          Hide
          ralfhandl Ralf Handl added a comment -

          Hubert, Martin, Gerald and I discussed this and we think that we don't need that distinction in the URL "signature"; it's a server secret of how it evaluates this expression.The Function element is just telling the client how to call it.

          We are not defining a programming language.

          Show
          ralfhandl Ralf Handl added a comment - Hubert, Martin, Gerald and I discussed this and we think that we don't need that distinction in the URL "signature"; it's a server secret of how it evaluates this expression.The Function element is just telling the client how to call it. We are not defining a programming language.
          Hide
          hubert.heijkers Hubert Heijkers (Inactive) added a comment -

          Correct, we don't think any consumer/client would need to know how/when the expression gets evaluated but the only 'missing' piece for generic consumers/clients would be the 'scope' in which the expression gets evaluated. In the TopN example we have in the description the value for N for exampe could have been "count() div 2" for example meaning I want the top half of the set. The N expression would be expected to execute in the scope of the collection where count would return the number of entities in that collection whereas the value expression is an expression that is executed within the scope of each and every entity in that collection. Generic query tools might/would need to know/understand this presumable. We discussed introducing an annotation for that which would effectively specify the scope, typically a type, in which the expression would be executed. Interesting remaining question though would be how to specify this for super functions that are not specifically bound to a particular type like TopN?

          Show
          hubert.heijkers Hubert Heijkers (Inactive) added a comment - Correct, we don't think any consumer/client would need to know how/when the expression gets evaluated but the only 'missing' piece for generic consumers/clients would be the 'scope' in which the expression gets evaluated. In the TopN example we have in the description the value for N for exampe could have been "count() div 2" for example meaning I want the top half of the set. The N expression would be expected to execute in the scope of the collection where count would return the number of entities in that collection whereas the value expression is an expression that is executed within the scope of each and every entity in that collection. Generic query tools might/would need to know/understand this presumable. We discussed introducing an annotation for that which would effectively specify the scope, typically a type, in which the expression would be executed. Interesting remaining question though would be how to specify this for super functions that are not specifically bound to a particular type like TopN?
          ralfhandl Ralf Handl made changes -
          Fix Version/s V4.0_WD01 [ 10247 ]
          Hide
          mikep Michael Pizzo (Inactive) added a comment -

          I don't think that leaving the scope of where the expression is evaluated up to the server works.

          As Hubert says, generic query building tools, as well as generic OData URL parser libraries, can't rely on back-end specific secrets in order to understand how to build/parse the request. That's why, even for the built-in any() and all() functions, we use lambdas to have a well defined way to represent expressions that should be passed to the function as opposed to evaluated in order to pass the value in to the function.

          If we wanted to implement such "super functions" we would need to do something like lambdas, including the ability to define a function signature that took a lambda of a particular type.

          I'm concerned about the complexity of adding this type of functionality to this release, in a general way, and getting it right.

          Show
          mikep Michael Pizzo (Inactive) added a comment - I don't think that leaving the scope of where the expression is evaluated up to the server works. As Hubert says, generic query building tools, as well as generic OData URL parser libraries, can't rely on back-end specific secrets in order to understand how to build/parse the request. That's why, even for the built-in any() and all() functions, we use lambdas to have a well defined way to represent expressions that should be passed to the function as opposed to evaluated in order to pass the value in to the function. If we wanted to implement such "super functions" we would need to do something like lambdas, including the ability to define a function signature that took a lambda of a particular type. I'm concerned about the complexity of adding this type of functionality to this release, in a general way, and getting it right.
          Hide
          hubert.heijkers Hubert Heijkers (Inactive) added a comment -

          The implementer of the function knows the scope of the expression so the producer/server doesn't have an issue. Relaxing the definition of a Function Parameter to allow common expressions gives us all we need in that respect and the type of the parameter would even tell the consumer what type the expression would have to produce. The only thing the consumer, especially those generic once, wouldn't know is 'what' the expression is going to be evaluated against. Typically this would the type of whatever the collection it acts on is holding but it could even be something else for some very fancy functions.

          We'd propose add annotations to give those generic query tools just enough information about these. Even if we introduced a special type, say expression, for those parameters the consumer would need additional information to understand the context in which this expression would be executed. Therefore we feel we wouldn't need an additional type, just he appropriate annotation(s).

          Show
          hubert.heijkers Hubert Heijkers (Inactive) added a comment - The implementer of the function knows the scope of the expression so the producer/server doesn't have an issue. Relaxing the definition of a Function Parameter to allow common expressions gives us all we need in that respect and the type of the parameter would even tell the consumer what type the expression would have to produce. The only thing the consumer, especially those generic once, wouldn't know is 'what' the expression is going to be evaluated against. Typically this would the type of whatever the collection it acts on is holding but it could even be something else for some very fancy functions. We'd propose add annotations to give those generic query tools just enough information about these. Even if we introduced a special type, say expression, for those parameters the consumer would need additional information to understand the context in which this expression would be executed. Therefore we feel we wouldn't need an additional type, just he appropriate annotation(s).
          ralfhandl Ralf Handl made changes -
          Status New [ 10000 ] Open [ 1 ]
          mikep Michael Pizzo (Inactive) made changes -
          Proposal Relax ABNF from

          functionExprParameter = functionParameterName EQ ( parameterValue / firstMemberExpr )

          to

          functionExprParameter = functionParameterName EQ ( parameterValue / commonExpr )
          Relax ABNF from

          functionExprParameter = functionParameterName EQ ( parameterValue / firstMemberExpr )

          to

          functionExprParameter = functionParameterName EQ ( parameterValue / commonExpr

          Note: this passes in the result of the expression to the function (not the expression)
          Hide
          sdrees Stefan Drees (Inactive) added a comment -

          Closed paren

          Show
          sdrees Stefan Drees (Inactive) added a comment - Closed paren
          sdrees Stefan Drees (Inactive) made changes -
          Proposal Relax ABNF from

          functionExprParameter = functionParameterName EQ ( parameterValue / firstMemberExpr )

          to

          functionExprParameter = functionParameterName EQ ( parameterValue / commonExpr

          Note: this passes in the result of the expression to the function (not the expression)
          Relax ABNF from

          functionExprParameter = functionParameterName EQ ( parameterValue / firstMemberExpr )

          to

          functionExprParameter = functionParameterName EQ ( parameterValue / commonExpr )

          Note: this passes in the result of the expression to the function (not the expression)
          ralfhandl Ralf Handl made changes -
          Resolution Fixed [ 1 ]
          Status Open [ 1 ] Resolved [ 5 ]
          ralfhandl Ralf Handl made changes -
          Assignee Ralf Handl [ ralfhandl ]
          ralfhandl Ralf Handl made changes -
          Component/s OData ABNF Construction Rules [ 10269 ]
          Component/s OData URL Conventions [ 10270 ]
          Component/s OData CSDL [ 10268 ]
          Environment [Proposed] [Applied]
          sdrees Stefan Drees (Inactive) made changes -
          Status Resolved [ 5 ] Applied [ 10002 ]
          sdrees Stefan Drees (Inactive) made changes -
          handl Ralf Handl made changes -
          Assignee Ralf Handl [ ralfhandl ] Ralf Handl [ handl ]

            People

            • Assignee:
              handl Ralf Handl
              Reporter:
              hubert.heijkers Hubert Heijkers (Inactive)
            • Watchers:
              0 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: