Interesting / strange code picked up from pluralsight training (functional programming)
-
It doesn't copy stdin to stdout. The only thing in common with "tee" is in the amount of parameters.
Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^] "If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.
Yes, you are correct. I think the point that the author/presenter was attempting to make is that you can output the value and continue processing the value as input to yet another function. That's why the author/presenter named the method Tee (which I hadn't seen before). I looked it up and found the associated wiki article and just thought that was an interesting piece of history.
-
Yes, you are correct. I think the point that the author/presenter was attempting to make is that you can output the value and continue processing the value as input to yet another function. That's why the author/presenter named the method Tee (which I hadn't seen before). I looked it up and found the associated wiki article and just thought that was an interesting piece of history.
raddevus wrote:
I think the point that the author/presenter was attempting to make is that you can output the value and continue processing the value as input to yet another function.
Like a decorator..
Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^] "If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.
-
raddevus wrote:
I think the point that the author/presenter was attempting to make is that you can output the value and continue processing the value as input to yet another function.
Like a decorator..
Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^] "If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.
Eddy Vluggen wrote:
Like a decorator..
cue Madonna
...touched for the very first time...
:laugh: I could not pass that up. Ignoring the bad joke (if possible) I think your point is really interesting, because it is like a decorator. Also, in an effort to completely beat this dead horse, how about the following addition? If, nothing else, the added method has a great name : see SpaceOut.
public static class Helper{
public static T Tee(
this T @inVal,
Action act){
act(@inVal);
return @inVal;
}public static Byte\[\] GetBytes( this String @inVal){ Byte \[\] outBytes = new Byte\[@inVal.Length\]; int loopCount = 0; foreach (Char c in @inVal){ outBytes\[loopCount\] = Convert.ToByte(c); loopCount++; } return outBytes; } public static String DisplayBytes(this byte\[\] inBytes){ String outVal = String.Empty; foreach (Byte b in inBytes){ outVal += Convert.ToString($"{b:D3} "); } return outVal; } public static String SpaceOut(this string @inVal){ StringBuilder spacedItem = new StringBuilder(); foreach (Char c in @inVal){ spacedItem.Append($" {c} "); } Console.WriteLine(spacedItem.ToString()); return @inVal; }
}
Now you can do this:
"What up!"
.Tee(Console.WriteLine)
.SpaceOut()
.GetBytes()
.DisplayBytes()
.Tee(Console.WriteLine);And you will get the following:
What up!
W h a t u p !
087 104 097 116 032 117 112 033Additionally interesting (or not) is that SpaceOut simply passes the input string along with no change since you only want the input to be printed with the extra spaces but don't want the output altered in this case. I got a million of 'em! :laugh:
-
Eddy Vluggen wrote:
Like a decorator..
cue Madonna
...touched for the very first time...
:laugh: I could not pass that up. Ignoring the bad joke (if possible) I think your point is really interesting, because it is like a decorator. Also, in an effort to completely beat this dead horse, how about the following addition? If, nothing else, the added method has a great name : see SpaceOut.
public static class Helper{
public static T Tee(
this T @inVal,
Action act){
act(@inVal);
return @inVal;
}public static Byte\[\] GetBytes( this String @inVal){ Byte \[\] outBytes = new Byte\[@inVal.Length\]; int loopCount = 0; foreach (Char c in @inVal){ outBytes\[loopCount\] = Convert.ToByte(c); loopCount++; } return outBytes; } public static String DisplayBytes(this byte\[\] inBytes){ String outVal = String.Empty; foreach (Byte b in inBytes){ outVal += Convert.ToString($"{b:D3} "); } return outVal; } public static String SpaceOut(this string @inVal){ StringBuilder spacedItem = new StringBuilder(); foreach (Char c in @inVal){ spacedItem.Append($" {c} "); } Console.WriteLine(spacedItem.ToString()); return @inVal; }
}
Now you can do this:
"What up!"
.Tee(Console.WriteLine)
.SpaceOut()
.GetBytes()
.DisplayBytes()
.Tee(Console.WriteLine);And you will get the following:
What up!
W h a t u p !
087 104 097 116 032 117 112 033Additionally interesting (or not) is that SpaceOut simply passes the input string along with no change since you only want the input to be printed with the extra spaces but don't want the output altered in this case. I got a million of 'em! :laugh:
:laugh:
raddevus wrote:
I got a million of 'em! :laugh:
Is that due to .NET being functional, or due to OO and your result being an object? :-\
Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^] "If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.
-
Eddy Vluggen wrote:
Like a decorator..
cue Madonna
...touched for the very first time...
:laugh: I could not pass that up. Ignoring the bad joke (if possible) I think your point is really interesting, because it is like a decorator. Also, in an effort to completely beat this dead horse, how about the following addition? If, nothing else, the added method has a great name : see SpaceOut.
public static class Helper{
public static T Tee(
this T @inVal,
Action act){
act(@inVal);
return @inVal;
}public static Byte\[\] GetBytes( this String @inVal){ Byte \[\] outBytes = new Byte\[@inVal.Length\]; int loopCount = 0; foreach (Char c in @inVal){ outBytes\[loopCount\] = Convert.ToByte(c); loopCount++; } return outBytes; } public static String DisplayBytes(this byte\[\] inBytes){ String outVal = String.Empty; foreach (Byte b in inBytes){ outVal += Convert.ToString($"{b:D3} "); } return outVal; } public static String SpaceOut(this string @inVal){ StringBuilder spacedItem = new StringBuilder(); foreach (Char c in @inVal){ spacedItem.Append($" {c} "); } Console.WriteLine(spacedItem.ToString()); return @inVal; }
}
Now you can do this:
"What up!"
.Tee(Console.WriteLine)
.SpaceOut()
.GetBytes()
.DisplayBytes()
.Tee(Console.WriteLine);And you will get the following:
What up!
W h a t u p !
087 104 097 116 032 117 112 033Additionally interesting (or not) is that SpaceOut simply passes the input string along with no change since you only want the input to be printed with the extra spaces but don't want the output altered in this case. I got a million of 'em! :laugh:
You look like a kid with brand shiny new shoes :rolleyes: :rolleyes: ;P ;P :laugh: :laugh:
M.D.V. ;) If something has a solution... Why do we have to worry about?. If it has no solution... For what reason do we have to worry about? Help me to understand what I'm saying, and I'll explain it better to you Rating helpful answers is nice, but saying thanks can be even nicer.
-
I like your questions because I'm learning the concepts and determining how these things are important too. And I can tell by your questions that you have more functional experience than I do. Here's an example that may make more sense -- it's like a before and after test.
Helper.Tee(Helper.Tee(" _ before after _ ", Console.WriteLine)
.ToUpper().Trim()
.Substring(8,6),
Console.WriteLine);That results in an output like the following:
_ before after _
AFTERBecause the Tee method returns the value methods can be chained just like the normal string methods and so you can see the BEFORE version of your string and then the AFTER version. I don't know if that is helpful either, but it's interesting. This was a very small portion of an example showing how to create fluent APIs.
Like Richard, I was thinking of an extension method. What you have there is pretty hard to read, took me a while to figure out what it does (due to the nested Tee, which is not a very helpful name either). I'm all for chaining though, that's what LINQ does too (which is pretty functional). Applying functional principles (but remembering C# is not a functional language) really helped me write cleaner and more succinct code. Although not everyone agrees with me, some people prefer their foreach loops and can't read lambda's :sigh: One thing I've learned, and taken to heart, a function has input and predictable output (no side-effects or state!). At some point you're going to have state and output, of course, but that's reserved for special classes. To give an example (from the top of my head, ignore bad practices such as public fields):
public class BadClass
{
public string s;
public void BadClass(string s)
{
this.s = s;
}public void DoubleString()
{
s = s + s;
}
}// Usage
var bc = new BadClass("Hello");
bs.DoubleString();
Console.WriteLine(bc.s); // HelloHellopublic class GoodClass
{
public void DoubleString(string s)
{
return s + s;
}
}// Usage
var gc = new GoodClass();
var s = gc.DoubleString("Hello");
Console.WriteLine(s); // HelloHelloIt's a bit contrived, but you'd be amazed at how often I've seen the BadClass implementation (equivalent) of this. People just love their state and side effects. But then again, I've worked on old VB applications with old VB programmers... As coincidence would have it Packt offers a free Functional C#[^] eBook today, may be interesting (haven't read it myself).
Best, Sander Continuous Integration, Delivery, and Deployment arrgh.js - Bringing LINQ to JavaScript Object-Oriented Programming in C# Succinctly
-
I was watching a very good intro to Functional programming on PluralSight (Functional Programming with C# | Pluralsight[^]) and the author / presenter created the following method (mine has altered var names).
public static class Helper{
public static T Tee(
T @inVal,
Action act){
act(@inVal);
return @inVal;
}
}Now you can call that method like the following:
Helper.Tee("test", Console.WriteLine);
Helper.Tee(3.238, Console.WriteLine);
Helper.Tee (new {garbage="super"},Console.WriteLine);Here's the output:
test
3.238
{ garbage = super }It's loosely based on the following idea (why it's named Tee): tee (command) - Wikipedia[^] Just thought it was an interesting example and it made me think differently about things. After all these years of OOP I'm beginning to see the real value in the Functional paradigm*. *Obviously the included sample is not a huge example of Functional programming in and of itself.
-
You look like a kid with brand shiny new shoes :rolleyes: :rolleyes: ;P ;P :laugh: :laugh:
M.D.V. ;) If something has a solution... Why do we have to worry about?. If it has no solution... For what reason do we have to worry about? Help me to understand what I'm saying, and I'll explain it better to you Rating helpful answers is nice, but saying thanks can be even nicer.
-
:laugh:
raddevus wrote:
I got a million of 'em! :laugh:
Is that due to .NET being functional, or due to OO and your result being an object? :-\
Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^] "If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.
-
Why is an @ sign being used for @inVal? Aren't those only used for naming a variable after a reserved keyword?
icemanind wrote:
Why is an @ sign being used for @inVal?
I wondered the same thing. This was the choice of the author/presenter and I hadn't seen that before either. He actually had his param named
@this
so it was even worse to me in that way. I didn't know C# allowed a var to be named with a beginning @ sign either, but apparently you can. -
icemanind wrote:
Why is an @ sign being used for @inVal?
I wondered the same thing. This was the choice of the author/presenter and I hadn't seen that before either. He actually had his param named
@this
so it was even worse to me in that way. I didn't know C# allowed a var to be named with a beginning @ sign either, but apparently you can.I knew you could have an @ sign in it. And it makes sense for @this because "this" is a reserved keyword in C#. Without the @ sign, naming a variable "this" would cause an error. But there is no keyword called "inVar", which is why I was confused about that one.
-
I knew you could have an @ sign in it. And it makes sense for @this because "this" is a reserved keyword in C#. Without the @ sign, naming a variable "this" would cause an error. But there is no keyword called "inVar", which is why I was confused about that one.
Honestly, it was me being ignorant. However, you've made me think about this and I get the point now. It sounds like I'm being sarcastic but I'm really not. I know this thread has been odd but it has really made me rethink and firstThink a number of things. :thumbsup:
-
Eddy Vluggen wrote:
or due to OO and your result being an object?
A valid point. :(( But, blithely I roll on. :laugh: Let's see. what else could I do to a String?... :rolleyes:
-
Ohh...look...I've really gone crazy with this now.
public static class Helper{
public static T Tee(
this T @inVal,
Action act){
act(@inVal);
return @inVal;
}public static Byte\[\] GetBytes( this String @inVal){ Byte \[\] outBytes = new Byte\[@inVal.Length\]; int loopCount = 0; foreach (Char c in @inVal){ outBytes\[loopCount\] = Convert.ToByte(c); loopCount++; } return outBytes; } public static String DisplayBytes(this byte\[\] inBytes){ String outVal = String.Empty; foreach (Byte b in inBytes){ outVal += Convert.ToString($"{b} "); } return outVal; }
}
Try it like this and you get before and after again:
"What up!"
.Tee(Console.WriteLine)
.GetBytes()
.DisplayBytes()
.Tee(Console.WriteLine);Output looks like:
What up!
87 104 97 116 32 117 112 33:cool: Well, it's fun.
Quote:
public static Byte[] GetBytes( this String @inVal){
Byte [] outBytes = new Byte[@inVal.Length];
int loopCount = 0;
foreach (Char c in @inVal){
outBytes[loopCount] = Convert.ToByte(c);
loopCount++;
}
return outBytes;
}That should probably be:
public static Byte[] GetBytes( this String @inVal ) => System.Text.Encoding.UTF8.GetBytes(@inVal);
Remember, some characters aren't single bytes. :)
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
Quote:
public static Byte[] GetBytes( this String @inVal){
Byte [] outBytes = new Byte[@inVal.Length];
int loopCount = 0;
foreach (Char c in @inVal){
outBytes[loopCount] = Convert.ToByte(c);
loopCount++;
}
return outBytes;
}That should probably be:
public static Byte[] GetBytes( this String @inVal ) => System.Text.Encoding.UTF8.GetBytes(@inVal);
Remember, some characters aren't single bytes. :)
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
Like Richard, I was thinking of an extension method. What you have there is pretty hard to read, took me a while to figure out what it does (due to the nested Tee, which is not a very helpful name either). I'm all for chaining though, that's what LINQ does too (which is pretty functional). Applying functional principles (but remembering C# is not a functional language) really helped me write cleaner and more succinct code. Although not everyone agrees with me, some people prefer their foreach loops and can't read lambda's :sigh: One thing I've learned, and taken to heart, a function has input and predictable output (no side-effects or state!). At some point you're going to have state and output, of course, but that's reserved for special classes. To give an example (from the top of my head, ignore bad practices such as public fields):
public class BadClass
{
public string s;
public void BadClass(string s)
{
this.s = s;
}public void DoubleString()
{
s = s + s;
}
}// Usage
var bc = new BadClass("Hello");
bs.DoubleString();
Console.WriteLine(bc.s); // HelloHellopublic class GoodClass
{
public void DoubleString(string s)
{
return s + s;
}
}// Usage
var gc = new GoodClass();
var s = gc.DoubleString("Hello");
Console.WriteLine(s); // HelloHelloIt's a bit contrived, but you'd be amazed at how often I've seen the BadClass implementation (equivalent) of this. People just love their state and side effects. But then again, I've worked on old VB applications with old VB programmers... As coincidence would have it Packt offers a free Functional C#[^] eBook today, may be interesting (haven't read it myself).
Best, Sander Continuous Integration, Delivery, and Deployment arrgh.js - Bringing LINQ to JavaScript Object-Oriented Programming in C# Succinctly
Hi Sander, Evidently PackT changes which book is free every day, so that one is no longer free. cheers, Bill
«... thank the gods that they have made you superior to those events which they have not placed within your own control, rendered you accountable for that only which is within you own control For what, then, have they made you responsible? For that which is alone in your own power—a right use of things as they appear.» Discourses of Epictetus Book I:12
-
I was watching a very good intro to Functional programming on PluralSight (Functional Programming with C# | Pluralsight[^]) and the author / presenter created the following method (mine has altered var names).
public static class Helper{
public static T Tee(
T @inVal,
Action act){
act(@inVal);
return @inVal;
}
}Now you can call that method like the following:
Helper.Tee("test", Console.WriteLine);
Helper.Tee(3.238, Console.WriteLine);
Helper.Tee (new {garbage="super"},Console.WriteLine);Here's the output:
test
3.238
{ garbage = super }It's loosely based on the following idea (why it's named Tee): tee (command) - Wikipedia[^] Just thought it was an interesting example and it made me think differently about things. After all these years of OOP I'm beginning to see the real value in the Functional paradigm*. *Obviously the included sample is not a huge example of Functional programming in and of itself.
Hi, Raddevus, Really enjoying this discussion ! It would be interesting if you could, somehow:
public static T TeeHee(this T tee, params Func[] funcs)
{foreach (var func in funcs) { // ??????? } return tee;
}
But, the obvious problem is that all the funcs have to have the same return type. cheers, Bill
«... thank the gods that they have made you superior to those events which they have not placed within your own control, rendered you accountable for that only which is within you own control For what, then, have they made you responsible? For that which is alone in your own power—a right use of things as they appear.» Discourses of Epictetus Book I:12
-
Hi Sander, Evidently PackT changes which book is free every day, so that one is no longer free. cheers, Bill
«... thank the gods that they have made you superior to those events which they have not placed within your own control, rendered you accountable for that only which is within you own control For what, then, have they made you responsible? For that which is alone in your own power—a right use of things as they appear.» Discourses of Epictetus Book I:12
Yeah, that's why I said "today" yesterday :)
Best, Sander Continuous Integration, Delivery, and Deployment arrgh.js - Bringing LINQ to JavaScript Object-Oriented Programming in C# Succinctly
-
Hi, Raddevus, Really enjoying this discussion ! It would be interesting if you could, somehow:
public static T TeeHee(this T tee, params Func[] funcs)
{foreach (var func in funcs) { // ??????? } return tee;
}
But, the obvious problem is that all the funcs have to have the same return type. cheers, Bill
«... thank the gods that they have made you superior to those events which they have not placed within your own control, rendered you accountable for that only which is within you own control For what, then, have they made you responsible? For that which is alone in your own power—a right use of things as they appear.» Discourses of Epictetus Book I:12
Func<T, TResult>
is covariant[^] on the return type, so you could pass in functions which returned a more derived type than the declared return type.public static T TeeHee<T>(this T tee, params Func<T, object>[] funcs)
{
foreach (var func in funcs)
{
object x = func(tee);
// ???
}return tee;
}
42.TeeHee(
i => i, // Func<int, int>
i => $"The answer is {i}", // Func<int, string>
i => new Answer(i) // Func<int, Answer>
);The more important question would be, what are you intending to do with the returned values?
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
Hi, Raddevus, Really enjoying this discussion ! It would be interesting if you could, somehow:
public static T TeeHee(this T tee, params Func[] funcs)
{foreach (var func in funcs) { // ??????? } return tee;
}
But, the obvious problem is that all the funcs have to have the same return type. cheers, Bill
«... thank the gods that they have made you superior to those events which they have not placed within your own control, rendered you accountable for that only which is within you own control For what, then, have they made you responsible? For that which is alone in your own power—a right use of things as they appear.» Discourses of Epictetus Book I:12