is there a reason for the type of the second operand must be int?
...
// I would like to do this
public static StringList operator<<(StringList list, string s) {
list.Add(s);
return list;
}
// but only int is supported...
...
EDIT:
Just for sure... I can overload operator* for get (for example) List of string
class MyString {
string val;
public MyString(string s) {
val = s;
}
public static List<string> operator*(MyString s, int count) {
List<string> list = new List<string>();
while (count-- > 0) {
list.Add(s.val);
}
return list;
}
}
...
foreach (var s in new MyString("value") * 3) {
s.print(); // object extension (Console.WriteLine)
}
// output:
// value
// value
// value
...
but cannot overload left shift, well known from C++ std (overloaded for output), because it was unclear?
Of course, it's just a decision of C# designers.
Still it can be overloaded on something unexpected/unclear (with int).
Really the reason is that it was made an unclear code?
Yes. It's because the language specification requires it:
When declaring an overloaded shift operator, the type of the first operand must always be the class or struct containing the operator declaration, and the type of the second operand must always be int.
The language designers didn't have to make that decision - it would have been possible for them to remove that restriction if the wanted to - but I think this part of the specification explains their reasoning for this (and other) restrictions on operator overloading:
While it is possible for a user-defined operator to perform any computation it pleases, implementations that produce results other than those that are intuitively expected are strongly discouraged.
They probably wanted the bitshift operators to always behave like bitshift operators, and not as something completely surprising.
Because you want your code to look like c++? Why not an extension method .Append( item ) that returns the source list.
public static class ListExtensions
{
public static List<T> Append<T>( this List<T> source, T item )
{
if (source == null)
{
throw new NullArgumentException( "source" );
}
source.Add(item);
return source;
}
}
Used as:
var list = new List<string>();
list.Append( "foo" )
.Append( "bar" )
.Append( "baz" );
Related
We're using groovy in a type-safe way. At some point I want to invoke a method with signature
void foo(GString baa)
As long the String I enter contains some ${baz} everything is fine, but when I use a pure String I get a compile error
foo("Hello, ${baz}") // fine
foo("Hello, world") // Cannot assign value of type java.lang.String to variable of type groovy.lang.GString
foo("Hello, world${""}") // fine but ugly
Is there a nice way to create a GString out of String?
EDIT
Guess I've oversimplicated my problem. I'm using named constructor parameters to initialize objects. Since some of the Strings are evaluated lazily, I need to store them as GString.
class SomeClass {
GString foo
}
new SomeClass(
foo: "Hello, world" // fails
)
So method-overloading is no option.
The solution is as mentioned by willyjoker to use CharSequence instead of String
class SomeClass {
CharSequence foo
}
new SomeClass(
foo: "Hello, world" // works
)
new SomeClass(
foo: "Hello, ${baa}" // also works lazily
)
There is probably no good reason to have a method accepting only GString as input or output. GString is meant to be used interchangeably as a regular String, but with embedded values which are evaluated lazily.
Consider redefining the method as:
void foo (String baa)
void foo (CharSequence baa) //more flexible
This way the method accepts both String and GString (GString parameter is automagically converted to String as needed). The second version even accepts StringBuffer/Builder/etc.
If you absolutely need to keep the GString signature (because it's a third party API, etc.), consider creating a wrapper method which accepts String and does the conversion internally. Something like this:
void fooWrapper (String baa) {
foo(baa + "${''}")
}
You can create overloaded methods or you can use generics; something as below:
foo("Hello from foo GString ${X}")
foo("Hello from foo")
MyClass.foo("Hello from foo GString ${X}")
MyClass.foo("Hello from foo")
// method with GString as parameter
void foo(GString g) {
println("GString: " + g)
}
// overloading method with String as parameter
void foo(String s) {
println("String: " + s)
}
// using generics
class MyClass<T> {
static void foo(T t) {
println(t.class.name + ": " + t)
}
}
I have a class that I wanted dynamic on what type to accept, but still be of type float. I have added an example class below. Simply put, I want a class that can contain either Ints or Floats (or abstracts(Float)), but the type parameter doesn't like being assigned something that should actually fit it.
class Container<T:Float>
{
public function new(aValue:T = 0.0)
{
}
public function example():T
{
return 16.0;
}
In this example, I get two compiler errors. The fist one is the default value of the constructor new(aValue:T = 0.0. A simple fix is to set the value as dynamic, but I like my code neater than this. The second error is in the return value of example(). It won't let me return 16.0, as it is not a T instance.
My question: Is this doable and, if not, should I either use different class definitions for every type?
I think the issue here is that you don't really need the generic type "T".
Here's what I came up with given your constraints. The class "Container" is not generic, and merely contains a Float constructor. This still allows it, however, to accept any value that can be implicitly cast to Float, which includes any abstract as long as they define casting rules.
package ;
class Main
{
public static function main()
{
new Container(); // default
new Container(1); // Int
new Container(2.3); // Float
new Container(new UnifiesWithFloat(4.5)); // Float abstract
}
}
class Container
{
public function new(aValue:Float = 0.8)
{
trace('aValue is $aValue');
}
}
abstract UnifiesWithFloat(Float) from Float to Float
{
inline public function new(value:Float)
{
this = value;
}
}
The only way I could come up for this issue with a cast and with own resolving of the optional parameters.
class Test {
static function main() {
$type(new Container(1));
$type(new Container(1).example());
new Container(1).example();
$type(new Container(1.0));
$type(new Container(1.0).example());
new Container(1.0).example();
}
}
class Container<T:Float> {
public var value:T;
public function new(aValue:T) {
this.value = cast (aValue != null ? aValue : 0);
}
public function example():T {
return cast 16;
}
}
This logs:
Test.hx:3: characters 14-30 : Warning : Container<Int>
Test.hx:4: characters 14-40 : Warning : Int
Test.hx:7: characters 14-32 : Warning : Container<Float>
Test.hx:8: characters 14-42 : Warning : Float
I can't seem to get this working, but I'd be surprised if it wasn't possible in Haxe.
I'm trying to pass a couple of Enum values defined in my game to a function, so that it can then concatenate them as String types and pass that to other functions.
Example:
// In a general Entity class:
public override function kill():Void {
messages.dispatchCombined(entityType, ListMessages.KILLED);
super.kill();
}
And in my Messages.hx class:
package common;
import msignal.Signal.Signal1;
/**
* A Message / Event class using Signals bound to String names.
* #author Pierre Chamberlain
*/
class Messages{
var _messages:MessagesDef;
public function new() {
_messages = new MessagesDef();
}
public function add(pType:String, pCallback:FuncDef) {
if (_messages[pType] == null) {
_messages[pType] = new Signal1<Dynamic>();
}
var signals = _messages[pType];
signals.add( pCallback );
}
public function dispatch(pType:String, pArg:Dynamic):Bool {
var signals = _messages[pType];
if (signals == null) return false;
signals.dispatch(pArg);
return true;
}
//Compiler doesn't like passing enums :(
public inline function addCombined(pSource:Enum, pEvent:Enum, pCallback:FuncDef) {
add( combine(pSource, pEvent), pCallback );
}
public inline function dispatchCombined(pSource:Enum, pEvent:Enum, pArg:Dynamic):Bool {
return dispatch( combine(pSource, pEvent), pArg);
}
//How can I just pass the enum "names" as strings?
static inline function combine(a:Enum, b:Enum):String {
return String(a) + ":" + String(b);
}
}
typedef MessagesDef = Map<String, Signal1<Dynamic>>;
typedef FuncDef = Dynamic->Void;
Note how addCombined, dispatchCombined and combine expect an "Enum" type, but in this case I'm not sure if Haxe actually expects the entire Enum "class" to be passed (ie: ListMessages instead of ListMessages.KILLED) or if a value should work. Anyways, compiler doesn't like it - so I'm assuming another special Type has to be used.
Is there another way to go about passing enums and resolving them to strings?
I think you need EnumValue as parameter type (if it is only for enum values), and use Std.String to convert to String values.
static inline function combine(a:EnumValue, b:EnumValue):String {
return Std.string(a) + ":" + Std.string(b);
}
Of course that can be written smaller using String interpolation:
static inline function combine(a:EnumValue, b:EnumValue):String {
return '$a:$b';
}
Of course that can be 'more dynamic' using type parameters:
static inline function combine<A, B>(a:A, b:B):String {
return '$a:$b';
}
There is totally no need to use Dynamic as suggested. If you use Dynamic, you basically turn off the type system.
live example:
http://try.haxe.org/#a8844
Use Dynamic instead of Enum or pass them as Strings right away since you can always convert to enum from String if you need it later.
Anyway pass the enum as enum:Dynamic and then call Std.string(enum);
EDIT: Using EnumValue is definitely better approach than Dynamic, I use Dynamic in these functions because I send more than just Enums there and I am not worried about type safety in that case.
The following C# program does what I expect, which is to output "First," "Second", "Third." However, when I change the type of foo in Main to dynamic, it raises an exception that says:
"Cannot implicitly convert type 'MyProgram.Program' to 'System.Collections.IEnumerable'. An explicit conversion exists (are you missing a cast?)"
Why does changing the type to dynamic break the code in this way?
Thanks!
using System;
namespace TestForEach
{
class Program
{
private int idx = -1;
public Program GetEnumerator() {
return this;
}
public string Current
{
get {
string[] arr = { "First", "Second", "Third" };
return arr[idx];
}
}
public Boolean MoveNext()
{
return ++idx < 3;
}
static void Main(string[] args)
{
Program foo = new Program();
foreach (var i in foo)
{
System.Console.WriteLine(i);
}
System.Console.ReadKey();
}
}
}
My guess is that it is because your Program implements the appropriate methods in order to be considered an iterator by the compiler.
An iterator is invoked from client code by using a foreach statement. For example, you can create an iterator for a class that returns the elements in reverse order, or that performs an operation on each element before the iterator returns it. When you create an iterator for your class or struct, you do not have to implement the whole IEnumerator interface. When the compiler detects your iterator, it will automatically generate the Current, MoveNext and Dispose methods of the IEnumerator or IEnumerator(Of T) interface.
When using the dynamic keyword, the compiler is unable to detect that Program is being used in in iterable context. Because of this, it does not generate the appropriate code in order for it to be used in a foreach loop.
I'm surprised it even compiles. The Program class needs to implement IEnumerable.
I have a function that returns objects of different types based on the parameter passed to this function.
Is it possible to add these different object types to a collection based on some identifier in C# 4.0?
Usually we do something like this
List or List
but i want one collection which can add object of any type.
Instead of just making a List<object> like other posters are recommending, you may want to define an interface eg IListableObject that contains a few methods that your objects need to implement. This will make any code using these objects much easier to write and will guard against unwanted objects getting into the collection down the line.
Yes, it is called object. Eg:
var objlist = new List<object>();
objlist.Add(1);
objlist.Add(true);
objlist.Add("hello");
You could use object[], List<object>, ArrayList, IEnumerable, ... but if those types have a common base type it would be better to stick to a strongly typed collection.
Really your collection should be as specific as you can make it. When you say
objects of different types
Do these objects have anything in common? Do they implement a common interface?
If so you you can specialise the list on that interface List<IMyInterface>
Otherwise List<object> will do what you want.
Update
No, not really.
I'm sorry but I'm going to question your design.
If you have a collection of different objects, how do you decide how to use one of the objects?
You're going to have a large switch statement switching on the type of the object, then you cast to a specific object and use it.
You also have have a similar switch statement in your factory method that creates the object.
One of the benefits of Object Orientation is that if you design your objects correctly then you don't need to do these large "If it's this object do this.Method(), if it's that object do that.OtherMethod()".
Can I ask, why are you putting different objects into the same collection? What's the benefit to you?
If you want a collection which can add objects of any type then List<object> is the most appropriate type.
Collections in earlier versions of C# (not generics) can contain any kind of objects. If they're value type, they will be boxed into object.
When you need to use them, you can just cast it to the original type.
You may use List<Type> to hold the type information, if that's what you want. And Type[], Hashtable, etc. are also fine. You can use typeof operator to get the type or use Object.GetType().
Also check out Dynamic type.
http://msdn.microsoft.com/en-us/library/dd264736.aspx
It will basically do the same thing.
My Suggestion:
public class ParamValue
{
object value = null;
public ParamValue(object val)
{
value = val;
}
public string AsString()
{
return value.ToString();
}
public int AsInt()
{
return int.Parse(value.ToString());
}
public int? AsNullableInt()
{
int n;
if (int.TryParse(value.ToString(), out n))
{
return n;
}
return null;
}
public bool AsBool()
{
return bool.Parse(value.ToString());
}
public bool? AsNullableBool()
{
bool b;
if (bool.TryParse(value.ToString(), out b))
{
return b;
}
return null;
}
}
public class Params
{
Dictionary<string, object> paramCol = new Dictionary<string, object>();
public void Add(string paramName, object value)
{
paramCol.Add(paramName, value);
}
public ParamValue this[string paramName]
{
get
{
object v;
if (paramCol.TryGetValue(paramName, out v))
{
return new ParamValue(v);
}
return null;
}
}
}
Use param class as a collectio to your values, you can convert the return to every type you want.
You could use a Tuple of Genric Types
public Tuple<T, T> MySuperMethod()
{
int number = 1;
string text = "Batman";
return new Tuple<int, string>(number, text);
}
The .NET Framework directly supports tuples with one to seven
elements. In addition, you can create tuples of eight or more elements
by nesting tuple objects in the Rest property of a Tuple object.
https://msdn.microsoft.com/en-us/library/system.tuple(v=vs.100).aspx