Kinetic Code Camp - Bring your skills, or lack thereof.. :dumpster_fire:

Quick answer: with the lambda expression you are telling it to iterate over the records in the dataset.table using the sum method on each TranQty item (field/column). Without the initial part how would it (compiler) know what items to sum? x is what rowset, dataset, table, column, list?

2 Likes

Insert → <Dear Uncle Kevin :rofl: >

dsReceipts.RcvDtl.Sum(x => x.ThisTranQty)

Well one area of confusion is there are 2 forms of lambda expression.

You have expressions, and statements.

What you have there, is an expression lambda.

The code above, in English says:

Please (be nice) return the sum of the field ThisTranQty from the RcvDtl table in the dsReceipts (TableSet or DataSet).

This part, is not lambda at all: dsReceipts.RcvDtl.Sum.
It is traditional Object Oriented Programming notation, so you have this:

decimal IamAvariableOffScreen = [Object][ChildObject][ExtensionMethodOnObjectByType]()

The next part is where the lambda is:

x => x.ThisTranQty

You can tell by the => operator.

This part defines that we’ll be working on x, and we will use the lambda operator => to define an “anonymous” “inline” “function” that returns the ThisTranQty field from x TO the Sum (Extension) Function.

The variable x will take on the value of what is fed in to it. In this case, it represents the RcvDtl table, as that is what we are running our extension method on.

We don’t see the magic Magic Fingers Family GIF of Sum here, but it takes a number of objects and does it’s thing. We are just using lambda to provide it the data.

I’ll explain further later, this is hard to get right and explain well.
This goes back to delegates, Actions, Funcs etc. I guess I will need to explain extension methods as well.

I will try to show how the cake :cake: is made eventually, but it’s a bit of a mouth full.

Chocolate Cake GIF


Fun fact, LINQ, is pretty much all extension methods, all the way down.

4 Likes

BTW, if I make a mistake, or explain something poorly, please feel free to correct me.

Preferably with sarcasm, wit, or memes.

If you provide all three you get a cookie. :cookie:

Cookie GIF by NBC

Because after all, I’m just here for the :heart: & memes. :rofl:
Just like Dave:

INTERCAL has many other features designed to make it even more aesthetically unpleasing to the programmer: it uses statements such as “READ OUT”, “IGNORE”, “FORGET”, and modifiers such as “PLEASE”. This last keyword provides two reasons for the program’s rejection by the compiler: if “PLEASE” does not appear often enough, the program is considered insufficiently polite, and the error message says this; if it appears too often, the program could be rejected as excessively polite. Although this feature existed in the original INTERCAL compiler, it was undocumented.

Hopefully, this is a good start :slight_smile:

Business Process Management (BPM) tools within the Kinetic application is a way of adding additional functionality, validating data or automation.

BPMs / Functions are simply macros which can be executed from a triggering mechanism.

The trigger could be when a method (event) is used, a database filed is updated (database), being invoked or in some cases when a scheduled task is ran.

There are 4 types within the BPM toolset:

1 - Data directives (Database driven)

A data directive is linked to the database table and is triggered by a database event, data directive are used to control data that may be affected by several different business objects. since implementing Kinetic usage of data directives has become drastically less.

Type Description
In-Trans You still have the opportunity to change data BEFORE it gets written to the DB. You can also abort the transaction if desired at this point
Standard he data has already been written to the DB. You cannot stop or reverse the change. it is done. but you can act on the fact that something has changed, and do some other action such as: update another UD Table, Send an EMAIL, etc.

2 - Method Directives (Business Object driven)

A Method directive is linked to the Business Object and is triggered when business object method is invoked. Business method are accessible via swagger as each BO namespace has a method API endpoint.

Within method directives the options to hook onto even Pre, Base and Post :

Type Description
Pre-Processing BPMs carry out their tasks before the base method is triggered so in this way you can do some validation and prevent the base method running by returning an error message.Typically this is used for data validation purposes.
Base Is used to completely override the core functionality of that method.Note this is very rarely used in Method directives and would strongly advise against this for method directives.
Post-Processing Carry out their tasks after the base method is triggered so in this way you can automate a further task after you know that the base method has run through successfully without error.

3 - uBAQ (Independent to the Business Activity Query (BAQ))

Type Description
Update.Pre-Processing Carries out their tasks before the base method is triggered so in this way you can do some validation and prevent the base method running by returning an error message.Typically this is used for data validation purposes.
Update.Base This would typically be used If using the BPM Directive Configuration within the BAQ without a BPM Update Processing Update Method being Defined.Typically to invoke some other additional functionality.
Update.Post-Processing Carry out their tasks after the base method is triggered so in this way you can automate a further task after you know that the base method has run through successfully without error.
GetList.Post Returns a data into Results table. Base implementation executes the underlying query, using the post method will execute once query has been returned.
GetNew.Post Adds a row into Results table. By default sets fields with initial values after the row has been added.
RunCustomAction.Base Handles custom actions assigned to the query. Executes as base as there is no default base action for the actionID.

Field Update & Field Validate have been omitted as have never used these methods

4 - Functions (Centralised library for re-usable code)

Functions are an evolution of the existing BPM data and method directives.

Function tools can orchestrate Kinetic Services into custom reusable logic you can apply to Kinetic - externally (using REST) or internally invoked from a BPM directive or another Function, or as a scheduled task.

Functions are grouped by library. A library can be published or unpublished (for example, when being developed or updated).

6 Likes

Just wanted to answer a few of these.

Regarding ISNULL vs = “” (double quotes) or '' (single quotes): With the latter, what we’re looking for is empty strings in a field that exists. What we’re searching for with ISNULL is records that do not exist. For example, in the below BAQ, I’m looking for OrderDtl records that are not on a shipment/PackList:

image

``
Alternatively, if I change the PackNum to '' (BAQ replaces this with “Empty string”), I get an error, because PackNum is not an nvarchar type field:


image

``
If I change that to a varchar field, like ShipDtl.LineDesc, I don’t get an error, but I also don’t get any rows returned. All those rows where PackNum is null are not returned, becuase LineDesc is also null, not an empty string:


image

``
Regarding LIKE, MATCHES, EXISTS, BEGINS, etc, I don’t really use MATCHES so I can’t speak to that. For the others, you just need to know the Syntax. In the below query, I’m searching for OrderDtl lines that aren’t on a shipment, where the PartNum begins with “DC”. In SQL, I would use OrderDtl.PartNum LIKE 'DC%'. In a BAQ, I can use the below SupQuery (or Table) Criteria. No % required:
image

``
However, with LIKE you do have to use the % wildcard:
image

``
For EXISTS, that’s used when you have another subquery, and you want to check if your field value exists in a specified field of the other subquery.

7 Likes

We can think of lambda expressions like this:

From thisList, for each item, give me its Name
     thisList.Select(   item  =>     item.Name);

The method used dictates how that item is used.
In LINQ, some of the most common set operations are:
Select - creates a set of the results (in the above example, it is a series of Names)
Where - each expression must evaluate to a Boolean (true or false), and the original item is added to the result set when the result for that item is true (i.e., all items which have Name longer than 5 characters)
First - is like Where, it just returns the first result (throws an error if there isn’t one)
FirstOrDefault - is like First, but returns the default value if there is none (usually null)
OrderBy/OrderByDescending - sort the set by the selected … (i.e., item => item.CreatedDate)
Count - Count() returns a count of all items, but you can put a “Where” lambda to return a count of items that meet a certain requirement (part of below example)

Depending on the context, all of these can also take more complex lambdas, too:

item => // In this case, item is a string (normally, you can tell from context)
    {
        var firstLetter= item.Substring(0, 1);
        int count = item.Count(letter => letter == firstLetter);
        if (count > 1)
        {
            return firstLetter + " appears multiple times in " + item;
        }
        return firstLetter + " appears once in " + item;
    }

LINQ-to-SQL is more limited, since the code is translated to TSQL at runtime - if you try to do something that is not possible in (or too complex for) a single SQL query, then it will throw up. Force execution by calling ToList (or similar), then you can do whatever you want to the result set.

5 Likes

Wonderful. I’m sure I’ll keep them straight in my head always.

Sarcastic Season 2 GIF by New Amsterdam

So, @CSmith makes a good point, which is to highlight that I botched the question a bit. (OK, not his point, but I wish I had worded it better.)

Really what I mean is that in the statement at hand…

dsReceipts.RcvDtl.Sum(x => x.ThisTranQty)

…Why do I even need the x at all, really? Why can’t I write

dsReceipts.RcvDtl.Sum(ThisTranQty)

or

dsReceipts.RcvDtl.ThisTranQty.Sum()

or something else without a lambda?

Because I can do

dsReceipts.RcvDtl.Count

and I get a count of the rows in the RcvDtl table.

But summing the values of a field in the table requires profoundly different syntax?

I think it’s to keep the syntax consistent across the different expressions. If you’re doing a .Where(), you can have the same field from different places.

dsReceipts.RcvDtl.ThisTranQty.Where(x=> x.myfield == othertable.myfield).Select(x=>x.myField2).FirstOrDefault();

So if you didn’t have the x=> in there, you could have ambiguous items. It’s better to have all of the lambda need the same syntax than to have special rules for each different thing it can do.

1 Like

Just remember the saying about programming in the springtime:

March comes in like a Linq and out like a Lambda

3 Likes

The point of a lamba in this case is to pass a function instead of piece of data or a field name. You could implement it the other ways you suggest, but they would not be as flexible. Actually, this works just fine:

List<float> numbers = new List<float> { 43.68F, 1.25F, 583.7F, 6.5F };

float sum = numbers.Sum();

Console.WriteLine("The sum of the numbers is {0}.", sum);

/*
 This code produces the following output:

 The sum of the numbers is 635.13.
*/

Because the lambda is shorthand for a function, you can easily add complexity

OrderHead.OrderDtl.Sum(x => x.OrderLineQty * x.UnitPrice)

(Pardon the incorrect names writing on the fly)

You might ask why can’t you still just write:

OrderHead.OrderDtl.Sum(OrderLineQty*UnitPrice)

And I think that mostly comes back to what @Banderson is talking about with ambiguous items, particularly because lambdas capture outer variables

1 Like

@Banderson’s point is definitely valid

RcvDtl is a collection of something. Count() is an extension method,
and while it may be considered by some to be LINQ, it’s not really.

While dsReceipts.RcvDtl.Sum(ThisTranQty) could technically be written as an extension method, it would not logically fit with how you select other things in LINQ.

2 Likes

C# is strongly-typed language: it won’t even try to sum RcvDtl objects, unless you tell it how to do that. The Lambda describes what you want to happen by returning a summable value (e.i., TranQty)

You could define a Func to do that:

Func<Erp.Tablesets.RcvDtlRow, decimal> ThisTranQty = (rcvDtl) => rcvDtl.TranQty;

Then that statement becomes valid and does what you expect.

Otherwise, it looks (to the compiler) like you’re sending a variable that has not been defined.

The commands are read linearly … so when it gets to RcvDtl.ThisTranQty, the compiler says “Hey! RcvDtlTable doesn’t have a property or extension method by that name … I don’t know what to do with this!” … so it won’t even try.

1 Like

Started a tools section:

1 Like

What is a Type?

According to Wikipedia:

In computer programming, a type system is a logical system comprising a set of rules that assigns a property called a type (for example, integer, floating point, string) to every term (a word, phrase, or other set of symbols). Usually the terms are various language constructs of a computer program, such as variables, expressions, functions, or modules.[1] A type system dictates the operations that can be performed on a term. For variables, the type system determines the allowed values of that term

That’s about as clear as mud isn’t it? festival mud GIF by Mitteldeutscher Rundfunk

Ok, English time, with examples.

Assuming you’ve read the section on variables, let’s proceed.


//[Type] [Variable Name] [Operator] [Value]
//The value of this variable is of Type "string" (text)
string donnaSummer = "She works hard for the money.";

//[Type] [Variable Name] [Operator] [Value]
//The value of this variable is of Type "int" (Integer)
int hitchhiker = 42;

ds


//Here is a function
//[Access Modifier] [Return Type] [Function(Method) Name] [ Input Parameters ([Type] [Variable Name]) ]
//You'll see two types in the signature, Return Type is bool (Boolean {true/false}), and the Input Parameters takes a string (text)
private bool AreYouRidiculous(string message)
{
    //Variable
    //[Type] [Variable Name] [Operator] [Value]
    bool output = true;

    //Something we do
    //Console WriteLine is a method that takes a TYPE of string (There are exceptions, they are not relevant here.)
    //[Method]( Input Parameters [Type -> string])
    Console.WriteLine(message);

    //This is a function, so we must have a return
    //This function must return a bool (Boolean)
    //We defined the "output" variable earlier as Type "bool", so we are good.
    //Return [Type]
    return output;
}

Types are not only simple types, like strings or numbers. They can also be objects, and depending on language, other constructs.

    //[Type] [Variable Name] [Operator] [Keyword] [Type]( [Constructor Values] )
    //This Type is an "object", specifically, an object of Type "DataTable".
    DataTable dt = new DataTable("MyCollectionOfPeopleToAnnoy");


    //This is a class object. It is an object. It is also a Type, called "Groot"!
    //[Access Modifier] [objectType: class][Name & Type]
    public class Groot
    {
        // [Type] [Special Keyword] [Variable Name] [Operator] [Value]
        // The "Special Keyword" here, "const", just makes this value immutable,
        // which means it cannot be changed... it is a "constant" by definition. This is set at compile time. 
        private const string speech = "I am Groot.";

        //[Access Modifier] [Return Type] [Function(Method) Name] [Input Parameters]
        public void Speak()
        {
            //[Method]( Input Parameters [Type -> string])
            Console.WriteLine(speech);
        }
    }


Different languages have differing Type “Systems”, but as for C#, here is a table that explains some of the “Base” Types.

Type Description Value
byte 8-bit unsigned integer 0 to 255
sbyte 8-bit signed integer -128 to 127
short 16-bit signed integer -32,768 to 32,767
ushort 16-bit unsigned integer 0 to 65,535
int 32-bit signed integer -2,147,483,648 to 2,147,483,647
uint 32-bit unsigned integer 0 to 4,294,967,295
long 64-bit signed integer -9,223,372,036,854,770,000 to 9,223,372,036,854,770,000
ulong 64-bit unsigned integer 0 to 18,446,744,073,709,551,615
float 32-bit Single-precision floating point type -3.402823e38 to 3.402823e38
double 64-bit double-precision floating point type -1.79769313486232e308 to 1.79769313486232e308
decimal 128-bit decimal type for financial and monetary calculations (+ or -)1.0 x 10e-28 to 7.9 x 10e28
char 16-bit single Unicode character Any valid character, e.g. a,*, \x0058 (hex), or\u0058 (Unicode)
bool 8-bit logical true/false value True or False
object Base type of all other types.
string A sequence of Unicode characters
DateTime Represents date and time 0:00:00am 1/1/01 to 11:59:59pm 12/31/9999

Season 3 Monday GIF by The Sinner

I hope this helps, I’m sure it can be expanded… (by someone :rofl: )

3 Likes

Statement Lambdas (Snippet)

Back on the subject of lambdas

We’ve already covered Expression lambdas here, and the posts above and below, so let’s move on to Statement lambdas.

You use statement lambdas, when you need to do more than one statement, or do some more complex logic than an expression statement.

For example:

//using LINQ here (I just make this crap up, who knows if this is remotely correct.)
string someString = Db.PerCon.Where(p => p.PerConID == "ROCK").FirstOrDefault()
    .Select(str =>
    {
        string t1 = p.Name.ToUpper();
        string t2 = p.FirstName.ToLower();
        string t3 = p.LastName.ToUpper();
        if(t3.Length() > t2.Length())
        {
            return "Yo";
        }
        else return "Bollocks";
    }); //I said it was gibberish, but it's logic.

//or an Event, in a form: (try not to do this)
UD01Form.Shown += (sender, eventArgs) =>
{
    someClassLevelVariable = ((Control)sender).Name;
    MessageBox.Show(JsonConvert.SerializeObject(eventArgs, Formatting.Indented));
};

And that’s pretty much it. It’s a method, where you can do what you want in it.

If y’all want more on this one, please ask a specific question, and I’ll see if I can answer it, or prod me with a needed example.

Aha! Got one:

//Returning a list of new object from LINQ AND manipulating the output with a filter.
//This is bs code, don't do this lol
var listOfPeople = Db.PerCon.Where(p => p.LastName.StartsWith("Q"))
    .Select(p =>
    {
        var person = new
        {
             name = p.FirstName + " " +  p.LastName,
             hasMiddle = !String.IsNullOrWhiteSpace(p.MiddleName)
        }; 

        if(person.HasMiddle) return new
        {
             name = p.FirstName + " " + p.MiddleName + " " + p.LastName,
             hasMiddle = !String.IsNullOrWhiteSpace(p.MiddleName)
        }
        else return person;
    }).ToList();

My examples suck today, but I hope it’s clear.

2 Likes

I’m back. Sorry in advance.

I’m still lost on the lambdas, but I am trying to figure out how to contribute here while not being too much of “that guy.”

So, you can skip this paragraph, but for context, I’m the widget guy. I’m low-code or die. Now, that still means some code, of course, and that’s why I am here infecting this thread. When I need code, it’s almost always going to be a one-line snippet that I can just hurl into a Set Variable widget, or worst-case, a few lines in a code block. I’m not looking to create my own classes or delegates or what have you; I can go as far as a Func<> and that’s about it.

With that, I have read the replies here several times and googled about lambdas, but nothing is connecting for me.

Am I beneath the intelligence of this thread? Probably. But then there’s “What is a variable,” and like the Jeopardy viewer who gets one question right and thinks, “I could totally be on that show,” I too feel like I can hang with the crew here.

So, all of that is to preface the simple point of: I simply don’t get it with lambdas.

Here’s what I am piecing together:

  1. Lambda expressions are a single line (no need for curly braces or other programmer stuff),
  2. Lambda statements are multi-line, with curly braces and semicolons galore, and the word return in there. But it’s essentially an expanded version of #1.
    a. (This doesn’t get me any closer to having a clue.)
  3. There’s a scope thing going on here (bet you didn’t know I knew that word).
    a. What’s funny is that several of you point out that lambdas can see outer objects (I see this is a trade phrase), implying that normal is that inner objects cannot see outer objects? Is that right?
    b. (I am used to innermost objects having the most limited scope - outer has global scope and can be seen by anything inside of it, while inner cannot be seen by outer unless you do something wacky.)
    c. (Still no closer to understanding)
  4. Can I get some parentheses on this?! What on earth is the order of operations here?
    image

I think it’s

Db.PerCon.Where((p => p.PerConID) == "ROCK")

I don’t even know if that would work or not, but my point is, is that what is logically happening?

But my most fundamental question is: What kind of thing is a lambda returning? Is it a list? Is it more like a representation of a field in a table?

I have to run, but that’s what I have so far. Thanks to anyone that might still be bearing with me.

I keep telling you…

Low-Code / Widgets / Bobbins → It’s Code
Low-Code / Widgets / Bobbins → It’s Code
Low-Code / Widgets / Bobbins → It’s Code

Post away, fill it up, teach us O’ wise one, just don’t ask me to touch your widgets…

disgusted new girl GIF

You’ll get no hate from me, just me silently (openly) judging your choices. :rofl:

This thread, is more about mindset and problem solving, than technique, even though technique is the way it’s being presented.

continue tv land GIF by #Impastor

3 Likes

I don’t believe you can access items outside your scope. In the following case:

ds.table.Where(x => x.field1 == value).Sum(y => y.field2)

“y” cannot be any row (not really a row, but whatever) that was already excluded in the Where call.

SIdenote: I didn’t have to use “y” in the second lambda. I could have used “x” in both, since the x variable is contained within the scope of the call. However, I always switch up the names because x & y represent two different things. YMMV.

Every good fantasy or scifi story has one character that’s a proxy for the audience, who doesn’t know the backstory and has to be there so everyone can slow down and explain things in plain English.

Those characters are vital and so are you.

2 Likes

You got it. (mostly) Sometimes you need return, sometimes not, depending on what you are doing.

Been working my whole life on getting one, and I don’t either. Cope.

No, you can always see items in your scope, and any enclosing scopes (scopes you are inside of)

Ok no, it’s

Db.PerCon.Where(p => p.PerConID == "ROCK")

That says Using the Db context, and from the PerCon table (object),
select objects Where match some criteria.

That criteria being defined by a lambda.

The lambda itself says: Define variable p, where p is being fed from the Db.PerCon rows (it is the rows (Maybe we need to define what extension methods are, that would make some of this clearer.)), and then creates an anonymous function that returns true or false → p.PerConID == "ROCK"

p => p.PerConID == "ROCK"

//is equivalent to

if(PerConID == "ROCK") return my row

It depends on the context.
In a where clause in linq, it’s true or false.
In a select statements, it’s fields or new objects.
In other contexts, you may return nothing at all.

Lambdas are not LINQ, but LINQ uses a lot of lambdas, don’t confuse the two.

1 Like