Is there a use for... [modified]
-
In my meanderings through weird code ideas, I wrote down some simple classes in C# based on the idea of "What if variables were typed based on what they returned when called, using that as what they are." So, for example, an equation that returns a double "is" a double (or derived from DTBase(double)); a DTFunc(string) that concatenates a string based on relevant factors "is" a string (or derived from DTBase(string)) and, of course, a DTVar(int) contains and "is" an integer. (Parenthesis substituted for angle brackets) Being as this website is about code and being that I wrote this in C#, I decided to see what other programming netizens might think of this idea, as well as the rather present idea that someone may have thought of this first. Thanks.
modified on Friday, August 26, 2011 9:16 PM
-
In my meanderings through weird code ideas, I wrote down some simple classes in C# based on the idea of "What if variables were typed based on what they returned when called, using that as what they are." So, for example, an equation that returns a double "is" a double (or derived from DTBase(double)); a DTFunc(string) that concatenates a string based on relevant factors "is" a string (or derived from DTBase(string)) and, of course, a DTVar(int) contains and "is" an integer. (Parenthesis substituted for angle brackets) Being as this website is about code and being that I wrote this in C#, I decided to see what other programming netizens might think of this idea, as well as the rather present idea that someone may have thought of this first. Thanks.
modified on Friday, August 26, 2011 9:16 PM
So what's the difference from the current state of things? :confused:
-
So what's the difference from the current state of things? :confused:
Currently? Invalid in current state of things:
double a = new Func(delegate() { 2 + 2; });
Granted, a very simple example, but it helps lay the groundwork for the second example. Valid in my Dynamic-Typed paradigm:
DTBase a = new DTFunc(delegate() { 2 + 2; });
Console.WriteLine(a.Call); // Output 4
a = (DTVar)5; // Conversion needed because DTBase is an abstract class.
Console.WriteLine(a.Call); // Output 5
// Equivalent of "1 + 1 = X", where DTEquation calculates "x".
DTBase a = new DTEquation((DTVar)1, new DTOperand[] { new DTOperand(MathOp.Add, (DTVar)1) });
Console.WriteLine(a.Call); // output 2And in that equation, I could have put any type derived from DTBase(double), including functions, dice rolls, or, yes, other equations. So not *quite* the current state of affairs. :)
-
In my meanderings through weird code ideas, I wrote down some simple classes in C# based on the idea of "What if variables were typed based on what they returned when called, using that as what they are." So, for example, an equation that returns a double "is" a double (or derived from DTBase(double)); a DTFunc(string) that concatenates a string based on relevant factors "is" a string (or derived from DTBase(string)) and, of course, a DTVar(int) contains and "is" an integer. (Parenthesis substituted for angle brackets) Being as this website is about code and being that I wrote this in C#, I decided to see what other programming netizens might think of this idea, as well as the rather present idea that someone may have thought of this first. Thanks.
modified on Friday, August 26, 2011 9:16 PM
For the amusement and edification of any readers - What may be the first actual DynamicTyped program (if someone else didn't yoink the idea first) Provided simply to provide actual code, it accepts a sequence of numbers and outputs a formatted string:
DTFunc f = new DTFunc(
a =>
{
string r = "";
while (a.Count > 0)
{
r += a.Call + ", ";
}
return r.Length > 0 ? r.Substring(0, r.Length - 2) : r;
}
);for (int i = 0; i <= 10; ++i) f.Args.Add = i; Console.WriteLine(f.Call);
Output: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 Now, if I change its arg type to DTBase(double), I could feed all kinds of things into there - Variables, equations, dice rolls, other functions, file reads (not currently, but potentially)...So long as they all returned a double when called.
-
For the amusement and edification of any readers - What may be the first actual DynamicTyped program (if someone else didn't yoink the idea first) Provided simply to provide actual code, it accepts a sequence of numbers and outputs a formatted string:
DTFunc f = new DTFunc(
a =>
{
string r = "";
while (a.Count > 0)
{
r += a.Call + ", ";
}
return r.Length > 0 ? r.Substring(0, r.Length - 2) : r;
}
);for (int i = 0; i <= 10; ++i) f.Args.Add = i; Console.WriteLine(f.Call);
Output: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 Now, if I change its arg type to DTBase(double), I could feed all kinds of things into there - Variables, equations, dice rolls, other functions, file reads (not currently, but potentially)...So long as they all returned a double when called.
Reading this code I don't have a clue what you are doing: the function(?) 'Call is not shown, the meaning of 'Args' is opaque.
"In the River of Delights, Panic has not failed me." Jorge Luis Borges
-
Reading this code I don't have a clue what you are doing: the function(?) 'Call is not shown, the meaning of 'Args' is opaque.
"In the River of Delights, Panic has not failed me." Jorge Luis Borges
Essentially? Adds the numbers 0 to 10 to the functions' arguments. The function then iterates through those arguments and constructs a comma-separated string. "Call" is a general property that returns "Whatever it is the object does/is". In the case of the function, it calls the function. In the case of DTArgs, it dequeues the next argument. In comment-o-vision:
// So, create a new function taking DTArgs as input, // which is in short a queue of doubles (or anything else we want) // The first type, in this case "double", is the type used by // the function's internal DTArgs. DTFunc f = new DTFunc( a => { // The function body. string r = ""; // While our DTArgs 'a' has values, while (a.Count > 0) { // Add the next argument to the string, followed by a comma. // a.Call dequeues and returns the next argument. r += a.Call + ", "; } // Chop off the last comma. return r.Length > 0 ? r.Substring(0, r.Length - 2) : r; } ); // The function needs arguments, for (int i = 0; i <= 10; ++i) // So add them. Granted, setting a property is not standard. // But, this code is in my "StrangeTest" project. // .Args is a property accessor to the functions' DTArgs. f.Args.Add = i; // Call the function and write the output to the console. Console.WriteLine(f.Call);
I have no idea how well I'm explaining things (which tends to make my explanations rather...Bad), but hopefully I've cleared up at least a little confusion. :)
-
In my meanderings through weird code ideas, I wrote down some simple classes in C# based on the idea of "What if variables were typed based on what they returned when called, using that as what they are." So, for example, an equation that returns a double "is" a double (or derived from DTBase(double)); a DTFunc(string) that concatenates a string based on relevant factors "is" a string (or derived from DTBase(string)) and, of course, a DTVar(int) contains and "is" an integer. (Parenthesis substituted for angle brackets) Being as this website is about code and being that I wrote this in C#, I decided to see what other programming netizens might think of this idea, as well as the rather present idea that someone may have thought of this first. Thanks.
modified on Friday, August 26, 2011 9:16 PM
-
Valid in current paradigm:
var a = 5.5;
Invalid in current paradigm, but valid if paradigm theoretically adopted by C#:
a = new func(delegate() { return 5.5; });
Using a theoretical library of additional functions, both are valid:
DTBase a = (DTVar)5.5;
a = new DTFunc(delegate() { return 5.5; });The key point is that, instead of being a specific type of variable, "a" is now defined by what you get when you call it.
-
In my meanderings through weird code ideas, I wrote down some simple classes in C# based on the idea of "What if variables were typed based on what they returned when called, using that as what they are." So, for example, an equation that returns a double "is" a double (or derived from DTBase(double)); a DTFunc(string) that concatenates a string based on relevant factors "is" a string (or derived from DTBase(string)) and, of course, a DTVar(int) contains and "is" an integer. (Parenthesis substituted for angle brackets) Being as this website is about code and being that I wrote this in C#, I decided to see what other programming netizens might think of this idea, as well as the rather present idea that someone may have thought of this first. Thanks.
modified on Friday, August 26, 2011 9:16 PM
And here is a heavily-commented "Guess My Number" game using this paradigm (granted, it's not runnable without the classes, but it is heavily-commented. Should I release that code? I've no idea if anyone is the least bit intruiged):
// A simple "Guess my number" program.
// The length of the number to guess. DTVar length = 7; // A starting phrase. Console.WriteLine("Guess my Number, a {0}-digit number.", length); // True if or when the player guesses entirely correctly. DTVar allCorrect = false; // A function that matches the output of two DTArgs arguments, // and returns a string with X's in all locations where they don't match. DTFunc matchingF = new DTFunc( (a, b) => { // Our return string. string r = ""; // If our first DTArgs has values remaining, while (a.Count > 0) { // We can call a DTArgs to return the next argument, // or we can convert it. // As DTBase works on the principle that // the thing is what it returns when called, // the conversion can be implicit. // A DTArgs is an argument queue, essentially. char a1 = a; char b1 = b.Call; // If the two characters match, add that character to the string. // if they don't match, add 'X' to the string. r += (a1 == b1 ? a1 : 'X'); } return r; } ); // A function to generate a new "phone number". DTBase numberF = new DTFunc( delegate() { // Stores "length" number of random integers from 0 to 9 in a string. string r = ""; // "length" may be a DTVar, but because the use is unambiguous, // it can use implicit conversion. for (int t = 0; t < length; ++t) r += Rand.Next(10); // Returns the string "phone number". return r; } );
-
And here is a heavily-commented "Guess My Number" game using this paradigm (granted, it's not runnable without the classes, but it is heavily-commented. Should I release that code? I've no idea if anyone is the least bit intruiged):
// A simple "Guess my number" program.
// The length of the number to guess. DTVar length = 7; // A starting phrase. Console.WriteLine("Guess my Number, a {0}-digit number.", length); // True if or when the player guesses entirely correctly. DTVar allCorrect = false; // A function that matches the output of two DTArgs arguments, // and returns a string with X's in all locations where they don't match. DTFunc matchingF = new DTFunc( (a, b) => { // Our return string. string r = ""; // If our first DTArgs has values remaining, while (a.Count > 0) { // We can call a DTArgs to return the next argument, // or we can convert it. // As DTBase works on the principle that // the thing is what it returns when called, // the conversion can be implicit. // A DTArgs is an argument queue, essentially. char a1 = a; char b1 = b.Call; // If the two characters match, add that character to the string. // if they don't match, add 'X' to the string. r += (a1 == b1 ? a1 : 'X'); } return r; } ); // A function to generate a new "phone number". DTBase numberF = new DTFunc( delegate() { // Stores "length" number of random integers from 0 to 9 in a string. string r = ""; // "length" may be a DTVar, but because the use is unambiguous, // it can use implicit conversion. for (int t = 0; t < length; ++t) r += Rand.Next(10); // Returns the string "phone number". return r; } );
Hi Narf, I think this kind of experimentation is a very cool thing to do: at a minimum you will come to a greater understanding of what the language limits are, and your creativity is definitely showing here ! I don't have the 'bandwidth' or inclination to study your code and figure out what you are doing, but it seems to me that you are moving C# one step past 'var' and 'dynamic' towards behaving like more loosely-typed languages (Haskell ? Ruby ?). For me there's so much built-in to .NET in its current highly-evolved state, that I am going to stick with it, as is ... and it's evolving rapidly. If I want a List of integers converted to a string, (as early as .NET 2.0, I believe), I can use Linq like this: (and there may well be a simpler way: I'm no expert on Linq): List s = new List {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}.ConvertAll(i => Convert.ToString(i)); So, please do, keep going, follow your vision ! Don't let those who 'don't get it' phase you in the least :) best, Bill
"In the River of Delights, Panic has not failed me." Jorge Luis Borges
modified on Monday, August 29, 2011 11:34 PM
-
In my meanderings through weird code ideas, I wrote down some simple classes in C# based on the idea of "What if variables were typed based on what they returned when called, using that as what they are." So, for example, an equation that returns a double "is" a double (or derived from DTBase(double)); a DTFunc(string) that concatenates a string based on relevant factors "is" a string (or derived from DTBase(string)) and, of course, a DTVar(int) contains and "is" an integer. (Parenthesis substituted for angle brackets) Being as this website is about code and being that I wrote this in C#, I decided to see what other programming netizens might think of this idea, as well as the rather present idea that someone may have thought of this first. Thanks.
modified on Friday, August 26, 2011 9:16 PM
-
I think there is an interesting discussion to be had here but I don't quite see what you are gaining over a Func<double> (with DTFunc<T>), or just a normal variable with DTVar.
I apologize if you did read this particular post, but it sounds like you didn't, so I'm reposting it. Valid in current paradigm:
var a = 5.5;
Invalid in current paradigm, but valid if paradigm theoretically adopted by C#:
a = new func(delegate() { return 5.5; });
Using a theoretical library of additional functions, both are valid:
DTBase a = (DTVar)5.5;
a = new DTFunc(delegate() { return 5.5; });The key point is that, instead of being a specific type of variable, "a" is now defined by what you get when you call it. If you're wondering what use being able to type variables by what they return when "called" is, a few suggested thoughts are:
Dictionary> formulasForGame; // Functions, equations, single variables and file reads.
List> urlRetrieval; // Retrieves urls from various places and sources. Optionally, a list of DTArgs.
List> chatRelays; // A set of functions that relay text strings for chat according to the specific sending needs of each specific receiver and sender.
And any other situation where you want a generic, quick way to access data by type, not implementation. That is to say, counting double and Func(double) as separate implementations, but the same type. Thank you for your patience and interest. :)
-
I apologize if you did read this particular post, but it sounds like you didn't, so I'm reposting it. Valid in current paradigm:
var a = 5.5;
Invalid in current paradigm, but valid if paradigm theoretically adopted by C#:
a = new func(delegate() { return 5.5; });
Using a theoretical library of additional functions, both are valid:
DTBase a = (DTVar)5.5;
a = new DTFunc(delegate() { return 5.5; });The key point is that, instead of being a specific type of variable, "a" is now defined by what you get when you call it. If you're wondering what use being able to type variables by what they return when "called" is, a few suggested thoughts are:
Dictionary> formulasForGame; // Functions, equations, single variables and file reads.
List> urlRetrieval; // Retrieves urls from various places and sources. Optionally, a list of DTArgs.
List> chatRelays; // A set of functions that relay text strings for chat according to the specific sending needs of each specific receiver and sender.
And any other situation where you want a generic, quick way to access data by type, not implementation. That is to say, counting double and Func(double) as separate implementations, but the same type. Thank you for your patience and interest. :)
This:
a = new func<double>(delegate() { return 5.5; });
... may be invalid if you declare a as double, but if you want this kind of flexibility, surely you can use Func<double> in most cases (and when you want a constant, write a lambda or anonymous delegate to return it, as here). I guess that is possibly useful in some cases though. What is the performance hit like on this? You are adding a lookup (or method call) each time the 'variable' is referenced? Have you considered:
public implicit operator T(DTBase<T> val) { return val.Value; }
public implicit operator DTBase<T>(T val) { return new DTVar<T>(val); }That would make your implementation almost transparent.
-
In my meanderings through weird code ideas, I wrote down some simple classes in C# based on the idea of "What if variables were typed based on what they returned when called, using that as what they are." So, for example, an equation that returns a double "is" a double (or derived from DTBase(double)); a DTFunc(string) that concatenates a string based on relevant factors "is" a string (or derived from DTBase(string)) and, of course, a DTVar(int) contains and "is" an integer. (Parenthesis substituted for angle brackets) Being as this website is about code and being that I wrote this in C#, I decided to see what other programming netizens might think of this idea, as well as the rather present idea that someone may have thought of this first. Thanks.
modified on Friday, August 26, 2011 9:16 PM
-
are you suggesting implicit casting of Func instances to T? or perhaps 'implicit resolving' would be a better term.
Implicitly storing anything that returns T when "called", in T.
-
Implicitly storing anything that returns T when "called", in T.
-
I believe that is simply alternative semantics to what i said ;P but its getting late now and the caffeine is wearing off so i can't be sure ..... my brain hurts
Func is only one thing that could be placed in T. A Queue would be equally qualified, as it has a candidate for calling that results in T.