Re: Consistency, Templates, Constructors, and D3
On Monday, 27 August 2012 at 12:51:48 UTC, F i L wrote: auto a = Point(int)[].new(5).new(1, 2); but then, I can see why someone would want the distinction so it's easier to understand what constructor belongs to the Array. Either way, I don't see any conflicts with the syntax I purposed. Except being somewhat unfamiliar with it, I can only look it over and go 'huh? what's going on?'. new being a keyword from C++ for allocate on the heap immediately makes this whole thing confusing. I would wonder myself: Is this on the stack or in the heap for the whole thing? Is Point a struct or a class? Then I wonder assuming that you get 5 for the length, then would all the elements be set the same or just the first one? Would new still be a key word? If not (and uses a regular function signature as you propose), then what if someone decided to use new for something other than allocation and returned something other than the type you were expecting from the view above? (Say, making a 2d matrix?) Sorry, there are just coming forward for me as I sit here reading it.
Re: Consistency, Templates, Constructors, and D3
On Monday, 27 August 2012 at 14:53:57 UTC, F i L wrote: in C#, you use 'new Type()' for both classes and structs, and it works fine. In fact, it has some benefit with generic programming. Plus, it's impossible to completely get away from having to understand the type, even in C++/D today, because we can always make factory functions: I'm sure in C# that all structs and classes are heap allocated (It takes after C++ very likely) that's the simplest way to do it. You can do that in C++ as well, but other than having to declare it a pointer first. In C++ they made structs 'classes that are public by default' by it's definition I believe. Considering how C++ is set up that makes perfect sense. FooType newFoo() { return new FooType( ... ); } void main() { auto f = newFoo(); // struct or class? } By looking at newFoo I'd say a class; But if like in C# I'm sure you can't tell the difference (But C++ with the pointer you can). And for factory functions I'd put them inside the struct/class, unless I had a compelling reason not to. class Record { static Record newRecord(string options) { Record rec = new Record(); // stuff building the complex record return rec; } } However, I do agree it would be nice having some kind of distinction between stack/heap allocation and copy/ref semantics. Because constructor names are completely arbitrary in my proposal, I think you could easily just choose a different name (say, 'new' vs 'set'). struct Foo { this set() { ... } } class Bar { this new() { ... } } void main() { auto f = Foo.set( ... ); // stack/copy auto b = Bar.new( ... ); // heap/ref } Again, this is just an arbitrary distinction and wouldn't be enforced, so third-party libs could choose something completely different... but then, they always could (like above) so it's benefit is debatable. I've had ideas before about having two different '=' operators for assignment and copy, but honestly, I think just looking up and understanding the types you're working with might be the best solution. A task much easier with proper IDE tooltips and the like. Would new still be a key word? No. You could just as easily name your constructor 'freshCopyYo()'. In fact, you often want multiple constructor names for different constructing procedures, like I explain in my original post. For instance if you're loading from a file, having a 'load()' constructor makes more sense than 'new()'. When converting from some other type, have a 'from()' constructor. The name implies the action, but they all "construct" the type: class Text { this new() // blank this new(string s) // basic constructor this from(int i) // convert from int this from(float f) // convert from float this load(string filename) // load from file } All of these are constructors, because they're return type is 'this'. They all implicitly allocate an object and have a 'this' reference. However, their names and implementations are completely arbitrary, which is a good thing because we need and use these arbitrary constructors all the time today, we just have to do it in a completely inconsistent way (static factory functions). And a postblits would end up being...? The extra 'this' makes it look like an obvious typo or a minor headache. this this(this){} //postblitz? Honestly I kinda like it how it is now. It's fairly clear and concise. Only if you start getting creative can it begin to get confusing; Then again in any language someone who decided to make it confusing would make it confusing regardless. -- enum JOJOJO = 100; class Jo { int jojo1; Jo jo(Jo JOO) { int jojo = 10; int joJo = JOJOJO; Jo JO = new Jo(); // and so on and so forth. } } // Make a new Jo! Jo newJo(){ return Jo.jo(null); } Jo something = newJo(); //now is this a class or a struct :P Right back at you. -- Seriously... Actually if you get it confusing enough you could submit it to The International Obfuscated C Code Contest. http://www.ioccc.org/ I would say if 'new' is part of the function name, it's returns a class. If it's referenced (or a pointer), it could be either. But not having a universal constructor would make creating an array with defaults impossible without declaring/hinting which one to use. It's one reason structs have to have good contents for all it's data members at compile-time, so you could create an array with defaulted information that works. If we take your approach and suggestion, which one should the compile assume? Something globalSomething; class Something { this defaultConstructor(); this duplicate(); //or clone this copyGlobalSomething(); this constructorWithDefault(int x = 100); } By signature alone... Which one? They are all legal, they are unique
Re: Consistency, Templates, Constructors, and D3
On Monday, 27 August 2012 at 22:44:53 UTC, F i L wrote: Era Scarecrow wrote: C# structs are allocated on the stack when they can be. In certain cases (they're class fields, they're boxed, etc..) they're heap allocated. So it will intentionally ignore 'new' and instead just call the constructor and decide if it should be heap or not? Sounds both helpful and harmful to me. By looking at newFoo I'd say a class; But if like in C# I'm sure you can't tell the difference (But C++ with the pointer you can). the 'auto' keyword kind negates the 'Type*' distinction. My point here is that you pretty much have to look up the type definition (or a tooltip) to understand what you're working with when factory functions are involved. I think that's why the naming should be something that sounds easy to follow or follows a particular style. The following should have no trouble figuring out even without seeing any documentation. Mind you i'm throwing this out there without a specific class in min. File inputFile = File.createHandle("some file"); inputFile.load(); inputFile.close(); The result is the same weather they're inside or outside a class, because, when used, all the coder sees is the function name to know about what it's returning. Wrong. If you have it within a class, you know it comes FROM that class. There may be multiple 'Records' depending on different projects or having compatible types. In my own factory function it polymorphs based on the input, so knowing the root class makes sense to me. In D there is a difference between structs and classes beyond what's in C++. The 'new' keyword helps us understand what kind of object is being created, and I enjoy that. However, my argument is in favor of consistency because right now factory-functions, which _are_ used a lot, completely hide that distinction on top of being inconsistent with "normal" type construction. And a postblits would end up being...? The extra 'this' makes it look like an obvious typo or a minor headache. this this(this){} //postblitz? I'm sure this case has an easy solution. How about: struct Foo { this new() { ... } // constructor this() { ... } // postblit } But now you're breaking consistency by not including a return type. maybe 'this this()' but that looks like a mistake or typo. If you're willing to use something without a return type, why not leave it 'this(this)'? Or rename it all together? 'this postblitz()'. Only if you start getting creative can it begin to get confusing; And I have to completely disagree with you here. Memory Pools are used everywhere in performance-critical code which needs a dynamic array of objects. At least half of all the "allocation" in game engines is done through factory functions that recycle objects. Wasn't there already a way to specify (or going to be) what you wanted to use an allocator? I thought i remember seeing an example in TDPL. And for overload distinction (new vs load), which is an issue beyond Memory Pools and effects and even larger codebase. There needs to be a consistent way to distinguish (by name) a constructor that loads from a file, and one that creates the object "manually". Isn't that more an API issue? If we take your approach and suggestion, which one should the compile assume? Something globalSomething; class Something { this defaultConstructor(); this duplicate(); //or clone this copyGlobalSomething(); this constructorWithDefault(int x = 100); } By signature alone... Which one? They are all legal, they are uniquely named, and they are all equal candidates. Order of functions are irrelevant. It could work identically to how D functions today. A 'new()' constructor would be part of the root Object classes are derived of, and structs would have an implicit 'new()' constructor. But new wouldn't be a constructor then would it? It would still be based on allocating memory that's optionally different. Constructor and allocation are two different steps; And for it to seamlessly go from one to another defaults to having a set default constructor. Let's assume... class Object { this new() { //allocate return defaultConstructor(); } this defaultConstructor() {} } Now in order to make a constructor (and then destructor) you either can: A) overload or use 'defaultConstructor', which would be publicly known B) overload new to do allocation the same way and call a different constructor and specifically add a destructor to make sure it follows the same lines. C) overload new to call the default allocator and then call a different constructor Now assuming you can m
Re: D-etractions A real world programmers view on D
On Tuesday, 28 August 2012 at 00:14:34 UTC, Chris Cain wrote: On Monday, 27 August 2012 at 23:28:31 UTC, SomeDude wrote: I wish Walter went on kickstarter to get public funds allowing him to hire a couple of full time developers. I would pitch in $150 for that. I'd throw in $50, or $10-$15 each month for as long as it was needed. Perhaps putting up a option to give donations via paypal or something. Then when he accumulates a thousand or something that would hire for a while, Maybe get some help from FSF as well.
Re: Consistency, Templates, Constructors, and D3
On Tuesday, 28 August 2012 at 21:01:52 UTC, David Piepgrass wrote: this this(this){} //postblitz? This is not an appropriate syntax, not just because it looks silly, but because a postblit constructor is not really a constructor, it's is a postprocessing function that is called after an already-constructed value is copied. So I don't think there's any fundamental need for postblit constructors to look like normal constructors. I'm sure this case has an easy solution. How about: struct Foo { this new() { ... } // constructor this() { ... } // postblit } But now you're breaking consistency by not including a return type. maybe 'this this()' but that looks like a mistake or typo. I don't see how "this this()" is any worse than "this(this)"; IMO neither name really expresses the idea "function that is called on a struct after its value is copied". But a postblit constructor doesn't work like normal constructors, so keeping the "this(this)" syntax makes sense to me even though it is not consistent with normal constructors. "this()" has the virtual of simplicity, but it's even less googlable than "this(this)". As long as it's an established standard it won't matter. With his insistence that constructors have a return type, then the postblit should too. Although keep in mind most likely you won't 'return' anything in constructors and it's assumed that 'return this;' is entered at the very last line (although that becomes a special case, and that makes it okay right?). And for overload distinction (new vs load), which is an issue beyond Memory Pools and effects and even larger codebase. There needs to be a consistent way to distinguish (by name) a constructor that loads from a file, and one that creates the object "manually". Isn't that more an API issue? Sorry, I don't follow. Having a named constructor compared to a default one. If there's only one type of constructor (although different ways to call it) then there shouldn't be an issue; Not really. But the problem was down to 'is this a struct or a class' problem. Could do Hungarian notation/prefixes; Then you're forced to know each time you use it (unless you use auto everywhere). struct MyStruct becomes struct Struct_MyStruct or struct S_MyStruct Same problem, how do you tell it ahead of time without completely rewriting the rules? leaving it as 'this' and '~this' are simple to remember and work with, and factory functions should be used to do a bulk of work when you don't want the basic/bare minimum. Sorry, I don't understand what you're getting it. I suspect that you're interpreting his proposal in a completely different way than I am, and then trying to expose the flaws in your interpretation of the proposal, and then I can't follow it because my interpretation doesn't have those flaws :) But our own opinions never have flaws :) Being able to name the constructor whatever you want although may sound nice likely is more a hassle than it's worth. Like namespace issues. I agree being able to override new could be useful for types of allocation, but the way he presented it suggested new was the constructor & allocator, meaning you'd have to have in depth detail of both steps in order to override it later. Abstraction then is thrown away and the black box method becomes a white/clear box method, encapsulation goes out the window. Make everything as simple as possible, but not simpler. -- Albert Einstein
Re: Why can't we make reference variables?
On Wednesday, 29 August 2012 at 01:28:49 UTC, Jonathan M Davis wrote: On Wednesday, August 29, 2012 02:21:28 Tommi wrote: Foreach loops can make reference variables, and function calls can do it for the parameters passed in. So, my question is, wouldn't it be better if we could, in general, make reference variables? Not going to happen. Unfortunately though, I don't remember all of Walter's reasons for it, so I can't really say why (partly due to complications it causes in the language, I think, but I don't know). Use a pointer, std.typecons.RefCounted, a class, or make your struct a reference type (which would probably mean having the data held in a separate struct with a pointer to it in the outer struct). It's really not hard to have a type which is a reference type if that's what you really want. You just can't declare a ref to a variable as a local variable. You would need a flag added to EVERY variable and item to specify if it was stack allocated or not. Otherwise it would be quite annoying to deal with. The compiler has to work blindly, assuming everything is correct. You can ref what you've been given but making more permanent references aren't possible without bypassing the safeguards. Assuming 'ref' works: struct S { ref int r; } //ref local variable/stack, Ticking timebomb //compiler may refuse void useRef(ref S input, int r) { input.r = r; } //should be good, right? S useRef2(S input, ref int r) { //Can declare @safe, right??? input.r = r; //maybe, maybe not. return S; } //Shy should indirect care if it's local/stack or heap? S indirect(ref int r) { return useRef2(S(), r); } //local variables completely okay to ref! Right? S indirect2() { int r; return useRef2(S(), r); } S someScope() { int* pointer = new int(31); //i think that's right int local = 127; S s; //reference to calling stack! (which may be destroyed now); //Or worse it may silently work for a while useRef(s, 99); assert(s.r == 99); return s; s = useRef2(s, pointer); //or is it *pointer? assert(s.r == 31); //good so far if it passes correctly return s; //good, heap allocated s = useRef2(s, local); assert(s.r == 127); //good so far (still local) return s; //Ticking timebomb! s = indirect(local); assert(s.r == 127); //good so far (still local) return s; //timebomb! s = indirect2(); return s; //already destroyed! Unknown consequences! } assuming a flag is silently passed to ensure if it is stack or heap allocated, then useRef2 silently becomes... //safe! But not C callable! S useRef2(S input, ref int r, bool __r_isHeap) { assert(__r_isHeap, "Cannot use a stack allocated variable!"); input.r = r; //now @safe-able! return S; } Or at the end of the scope it could check all structs if the ref's had a silent flag specifying if a referenced variable was set for local, so it would assert/throw an exception at the end of the call. Am I wrong?
Re: Why can't we make reference variables?
On Wednesday, 29 August 2012 at 02:57:27 UTC, Era Scarecrow wrote: You would need a flag added to EVERY variable and item to specify if it was stack allocated or not. Otherwise it would be quite annoying to deal with. The compiler has to work blindly, assuming everything is correct. You can ref what you've been given but making more permanent references aren't possible without bypassing the safeguards. To add on to this a little.. If you can only ref by calling, you ensure the variable is alive/valid when you are calling it regardless if it's stack or heap or global (But can't ensure it once the scope ends). Making a reference as a variable modifier won't work, but using a pointer you're already going lower level and it's all up to you the programmer to make sure it's right. I think that's right; Otherwise ref wouldn't be allowed in @safe code (at all).
Re: Why can't we make reference variables?
On Wednesday, 29 August 2012 at 04:54:31 UTC, Tommi wrote: On Wednesday, 29 August 2012 at 03:17:39 UTC, Era Scarecrow I think that's right; Otherwise ref wouldn't be allowed in @safe code (at all). But couldn't the compiler disallow all unsafe ref use in @safe code, and allow all use of ref in @system and @trusted code? So Ref can only then be used if it's heap allocated... That would be the only @safe way, but even that is ridden with timebombs. int[10] xyz; foreach(i; xyz) { //all's good, they are copies! } foreach(ref i; xyz) { // cannot use ref, (not even const ref) as it may be unsafe } //a ref function void func(ref int i); int *z = new int; func(z); //or is it *z? 'Might' be good func(xyz[0]); //Compile error, may be unsafe. class C { int cc; } struct S { int sc; } C cSomething = new C(); S sSomething = S(); S* sSomething2 = new S(); func(cSomething.cc); //good, heap allocated enforced func(sSomething.sc); //error, may be unsafe! func(sSomething2.sc); //pointer dereference; It bypasses protections since it probably is heap (but not guaranteed), so maybe this should fail too. sSomething2 = &sSomething; func(sSomething2.sc); //back to a timebomb situation but the compiler can't verify it! only something from a class could be considered safe (maybe) Why is it unsafe? Let's assume we did this: ref int unsafe; //global ref. Hey it's legal if ref is allowed as you want it! void func(ref int i) { unsafe = i; } Now I ask you. If any of the 'unsafe' ones were used and then the scope ended that held that information and we use unsafe now, it can only be a time bomb: All of them stem from them being on the stack. void someFunc() { int stacked = 42; func(stacked); } someFunc(); writeln(unsafe); //what will this print? Will it crash? //some scope. FOR loop? IF statement? who cares? { int local = 42; func(&local); //assuming the pointer bypasses and gets dereferenced to get past the heap only compiler problems (pointers and classes only) limitations writeln(unsafe); //prints 42 as expected } writeln(unsafe); //? Scope ended. Now what? can't ensure local exists anymore as we reffed a stack class Reffed { ref int i; } //some scope Reffed r = new Reffed(); Reffed r2 = new Reffed(); @trusted { int local; r.i = local; //may or may not work normally, @trusted should force it } //Why not copy a reference from a class? //it should be good (heap only), right? r2.i = r.i; writeln(r.i); //? writeln(r2.i); //?!?! To make it 'safe' the only way to do it is ref can only be used on heap allocated data (or global fixed data). The current implementation as I see it anything referenced is safe because you can only reference something that currently exists (via function calls). The other way to make it safe is to silently include a flag that specifies if it was stack allocated or not, but even that becomes more complicated and more of an issue.
Re: Why can't we make reference variables?
On Wednesday, 29 August 2012 at 12:41:26 UTC, Tommi wrote: I think we might be talking about somewhat different things. What I mean by reference variable is what the term means in C++. From wikipedia: http://en.wikipedia.org/wiki/Reference_%28C%2B%2B%29 C++ references differ from pointers in several essential ways: * It is not possible to refer directly to a reference object after it is defined; any occurrence of its name refers directly to the object it references. * Once a reference is created, it cannot be later made to reference another object; it cannot be reseated. This is often done with pointers. *References cannot be null, whereas pointers can; every reference refers to some object, although it may or may not be valid. Note that for this reason, containers of references are not allowed. * References cannot be uninitialized. Because it is impossible to reinitialize a reference, they must be initialized as soon as they are created. In particular, local and global variables must be initialized where they are defined, and references which are data members of class instances must be initialized in the initializer list of the class's constructor. For example: int& k; // compiler will complain: error: `k' declared as reference but not initialized Then most of my examples change to going into the constructor rather than out, and the global one goes away. But it still doesn't help with the problem of anything stack allocated. struct S { //default construtor otherwise then fails to work because of ref? Since //x must be known at compile time so it would be null to start with, or no //default onstructor ref int x; this(ref int r) { x = r;} } S func() { int local = 42; S s = S(local); return s; } S func(ref int reffed) { S s = S(reffed); return s; } S s = func(); writeln(s.x); //mystery value still! { int local = 42; s = func(local); writeln(s.x); //42 } writeln(s.x); //!?!? Unless I'm understanding this wrong (And I'm tired right now maybe I missed something), once again the only safe 'reference variable' is from actively being called from a live accessible reference; And anything else is still a ticking timebomb and cannot ever be @safe. Stuff referencing within heaped/class related stuff may suffer fewer problems, but only as long as you rely on the GC and not do any magic involving malloc/free, or maybe a dynamic range. Reminds me. The example for the foreach are missing parts. int[10] fixed; int[] dynamic; dynamic.length = 10; foreach(i; fixed) { //fine, i is a copy } foreach(ref i; fixed) { //compile-time error for @safe checking //cannot ensure this is safe otherwise } foreach(i; dynamic) { //fine, i is a copy } foreach(ref i; dynamic) { //Dynamic/heap allocated, so fine. } //from function/ref void func(int[] huh) { foreach(ref i; huh) { //? safe? } } //both legal last I checked. func(fixed); func(dynamic); My god, as I look at this more, reference variables would cripple D so badly C++ wouldn't look half bad afterwards.
Re: Consistency, Templates, Constructors, and D3
On Wednesday, 29 August 2012 at 15:07:42 UTC, F i L wrote: Actually, now that I think about it, there's an potentially better way. Simply have static analysis do the work for us: class A { int a; this new() { // if 'this = ...' is found before 'this.whatever' then // the automatic allocation is overriden. So we have no need // for any kind of @noalloc/@alloc() distinction. // More importantly, because allocation is type specific, we // strip this out when calling it from a derived class (see B) this = GC.alloc(A); // this stripped when called from B.new() this.a = ...; } } class B : A { int b; this new() { super.new(); // use A.new() except for allocation this.b = ...; } } Basically what's happening is two functions are built out for each class constructor which defines a 'this = ...': one with the allocation stuff, and one without. When a derived class calls the super classes constructor, it's calling the one built without the allocation stuff. There could also be some kind of cool tricks involved. For instance of you use 'typeof(this)' with 'GC.alloc()' (instead of 'A'), then it could keep the allocation stuff and the super.new() constructor and use the allocation logic, but still allocate the size appropriate for type 'B' when it's called: class A { this new() { if (condition) { this = GC.alloc(typeof(this)); } else { this = malloc(typeof(this)); } ... } } class B { this new() { super.new(); // same allocation rules as A ... } } However, that last part's just a side thought, and I'm not sure if it would really work, or what the implementation costs would be. By this form of definition that's all suggested, you'd be mixing if it was heap or non-heap allocated. I'm not talking about Class A & B, I'm talking about things they contain. Assume class B was defined instead. class B : A { C something; this new() { super.new(); // same allocation rules as A ... something = new C(); //and however it's made } } Now you have the following: 1) Sometimes A/B is heap and sometimes not 2) Class C may or may not be heap allocated we don't know (It's an implementation detail) If A/B happens to be stack allocated then when it leaves the frame (or abandoned), no harm done (C is abandoned and will be picked up by the GC later safely) Let's reverse it so C is the outer class, and let's assume A is defined to use something like... alloca (stack). Now you have: class C { B mysteryNew; this new() { mysteryNew = new B(); } } Oops! Now leaving new (or the constructor, or whatever) mysteryNew is now an invalid object! So if there's another new option you can decide 'maybe' which one you may want to use. int currentCounter; B[10] globalReservedB; class C { B mysteryNew; this new1() @alloc { if (currentCounter < globalReservedB) { //because it's faster? And we all know faster is better! globalReservedB[currentCounter] = new1 B(); mysteryNew = globalReservedB[currentCounter++]; } else assert(0); } } Whew! Wait! No globalReservedB still is just a reference pointer and not preallocated space, meaning you'd have to do fancy low level magic to actually store stuff there. mysteryNew now points to a global reference holder that holds an invalid pointer. Say the authors of zlib make a D class that does compression at a low level because D is better than C. By default they used the standard new. LATER they decide that zlib compression should only happen on the stack because you only need to compress very very small buffers (for something like chat text where you only have maybe 4k to worry about), so they override new with their own that uses alloca. They don't want to change it to a struct because it's already a class. Now what?? There's no guarantees anymore at all! If you update a library you'd need to read every implementation detail to make sure the updates don't break current code and maybe add checks everywhere. What a headache! interface IZlib { void compress(string input); string decompress(string input); ubyte[] flush(); void empty(); } //intended use. ubyte[] compressText(string text) { Zlib zText = new Zlib(); zText.compress(text); return zText.flush(); } //our fancy function wants to do multiple reads/writes. Zlib compressText(Zlib zText, string text) { if (zText is null) zText = new Zlib(); zText.compress(text); return zText; } Assuming it allocates on the heap and where we assumed it would always go, the function probably would work fine. If Zlib changed to alloca since it should never be used otherwise (and they even make an explicit note), but it could break previously compiled code. class Zlib : IZlib { ... } //could contain mystery allocator IZlib ztext = compress
Re: Why can't we make reference variables?
On Wednesday, 29 August 2012 at 19:55:08 UTC, Tommi wrote: I honestly don't know anything about memory safety and what it entails. So, I can't comment about any of that stuff. But if you say general ref variables can't be implemented in @safe mode, then I can just take your word for it. But what I'm saying is that ref variables would be a nice feature to have in @system code. They can be used safely if they are heap allocated (or global). My logic is very simple: since we can use pointers in @system code, and references are no more unsafe than pointers, then we should be able to use references in @system code. You might argue that references are little more than syntactic sugar (and a bit safer) compared to pointers, but you shouldn't underestimate the importance of syntactic sugar especially when you're trying to lure in users of C++. Maybe. But the scope of referencing variables should likely be left alone. I am not sure of all the details of C++ references either. Ref hides the fact it's a pointer/reference. This means unless you really know what you're doing that it is not a good thing to use. Let's assume we compare a pointer and a ref in a struct and copying. struct P { int* ptr; } struct R { ref int r; this(ref int i) {r = i;} } int value; P p1, p2; p1.ptr = value; //Compile error, not a pointer, need to use &value p2 = p1; p2.ptr = 100; //compile error, need to use *p2.ptr = 100 value = 42; R r1 = R(value) R r2 = r1; //both reference value now r2.r = 100; //r must be a variable if this succeeds assert(r1.r == 42, "FAIL!"); assert(r2.r == 100, "Would succeed if it got this far"); If I have this right, as a pointer you know it's a pointer/reference and don't make more obvious mistakes as you're told by the compiler what's wrong. Also since it hides the fact it's actually a pointer hidden bugs are bound to crop up more often where reference variables were used. If we return now r1 or r2, it silently fails since it can't guarantee that the reference wasn't a local stack variable, or of anything at all really. As a pointer you can blame the programmer (It's their fault afterall), as a reference you blame the language designer. What would you do for the postblitz if you can't reset the reference? Or if you could, would you do...? It would be so easy to forget. this(this) { r = new int(r); } *Prepares for flames from Walter and Andrei*
Re: D-etractions A real world programmers view on D
On Thursday, 30 August 2012 at 17:52:27 UTC, Steven Schveighoffer wrote: An interesting point of view, and I can see how paying someone could be misconstrued. If Walter was given money to hire people, and he hired certain already-active members of the community, it might leave some thinking "why them and not me?" One thing I think would pose a large dilemma is who do you pay? Someone who is very active in contributing to D may not be able to contribute more, simply because there are just so many hours in a day. I'm amazed sometimes as to how some people do so much work on D! This means we're just handing out bonuses without getting much back. In my view this has very little to do with money, it has to do with time. Most likely most of us are freelancers or doing something that isn't getting us some 60k a year (or more) jobs, and although some of us likely are more skilled and able to take those jobs, the economy prevents to a degree. I would see the donations being used to hire someone NOT as a bonus or as incentive, but to allow them to tell their work place "hey I'll be taking a month off". If they love programming they may very well give more than their $15-$20/hr (or whatever is decided) wage they are accepting for the work; I know I certainly would.
Re: pointers, functions, and uniform call syntax
On Monday, 3 September 2012 at 18:45:42 UTC, Jonathan M Davis wrote: However, one thing to remember that complicates this a bit is that it's perfectly possible to declare a function which is overloaded with one function taking a pointer and one not. void func(S* s, int i) {...} void func(S s, int i) {...} in which case, there's an ambiguity, and I would then expect UFCS to _not_ compile when using S*, or you'd risk function call hijacking. That's not necessarily a big deal, but it _does_ complicate things a bit. - Jonathan M Davis I think moreso is would if it would convert to ref automatically or not rather than worry about pointers. True if you wanted all three, then the language has to keep them all distinctly different; But if it silently converts it should be okay (so long as constness/immutable is honored). Assuming that's the case: //these two effectively identical void func(S* s, int i) {...} void func(ref S s, int i) {...} I can see allowing a pointer be silently converted to a reference safely, however a normal to a pointer not so easily, not so much for type safety but accidents could be prone to happen. So... void funcP(S* s) {...} void funcR(ref S s) {...} struct S{} S *sp; //pointer S ss; //stack funcP(sp); //obviously will work fine funcP(ss); //error, pointer conversion may be confused for heap allocation funcR(sp); /*silently converting is acceptable as long as const/immutable is honored */ funcR(ss); //normal use as is used now. The reason it could be allowed as ref and not a pointer is the same as the argument for if you can have ref variables. If it's part of the function calling signature, you're guaranteed it's a live/valid item being passed, but a pointer would be required if it was a member item. However silently converting may have the result where functions using ref may suddenly have new issues if you can have a null reference (not normally possible), and it's impossible to check. S *p; //we know it's null funcR(p); //silently converts void funcR(ref S s) in{ //can't check for a null reference! It's not a pointer! } body { //time bomb with odd error when used? } Currently if I have it right, it would break if the object was invalid (during dereference/copying); You would have a more accurate error message that way (I'm certain). As a workaround you can have both functions and one call/convert to the other for you. With the workaround being this simple/small it's a very small price to pay; I would say automatically converting a pointer to a reference is likely something to be discussed; But I honestly would be against it for safety reasons. //maybe a ref or const versions as appropriate. void func(S s, int i) {...} //pointers should be the same (in my code) so here's my workaround! void func(S *s, int i) { func(*s, i); }
Re: pointers, functions, and uniform call syntax
On Tuesday, 4 September 2012 at 10:51:36 UTC, Artur Skawina wrote: On 09/03/12 20:45, Jonathan M Davis wrote: It's a perfectly valid enhancement request to want void func(S s, int i) {...} to be be callable with S*, given that normally function calls on an S* don't require you to dereference anything. No, it's not. See http://d.puremagic.com/issues/show_bug.cgi?id=8490 for why this would be a very bad idea. However 'void func(ref S s, ...){}' should (be made to) work, at least for the UFCS case - if it already doesn't (old compiler here...) - if 'func' is supposed to emulate a method then it should behave like one. Hmmm... And here i consider the opposite true. With ref as it works, you can only pass 'live' (absolutely guaranteed to be allocated) variables to work, you can't guarantee that with a normal pointer. On the other hand. Let's consider the two calls. struct S { int x, y; int gety(){ return y;} } int getx(S s) {return s.x;} S ss; S *sp = &ss; //without errors for now writeln(ss.gety()); writeln(sp.gety()); /*pointer but as it currently works, the same (technically) */ writeln(ss.getx()); writeln(sp.getx()); //currently breaks without dereferencing If getx is valid with a pointer, it will be more consistent (and doesn't change anything). Now let's void it. sp = null; writeln(sp.gety()); //null pointer, refers to calling site writeln(sp.getx()); /*null pointer, breaks during copying and should refer to calling site*/ This I think is totally acceptable since it would be the same error and the same reason. If we take ref and allow that, you may as well allow referencing variables (and not just in the function signature) struct S { //may as well allow during building of struct, //it's just as safe as the rest of the ref calls now. ref S prev; //defaults to null this (ref S s) {prev = s}; int x; } int getx(ref S s) {return s.x} //now breaks inside getx writeln(sp.getx()); writeln(getx(sp)); //might compile?; More likely it's no longer a named variable writeln((*sp).getx()); writeln(getx(*sp)); //might compile, but now it's old C/C++ pointers. Very risky? writeln(getx(sp[0])); I ask you, how do you check if it's a null pointer? &s? int getx(ref S s) //How does this make sense?? it looks wrong and is misleading in {assert(&s); } body {return s.x); } More importantly, if it's now a possibility do we have to start adding checks everywhere? int getx(S *s) in {assert(s); } //perfectly acceptable check, we know it's a pointer body {return s.x); }
Re: pointers, functions, and uniform call syntax
On Wednesday, 5 September 2012 at 11:01:50 UTC, Artur Skawina wrote: On 09/04/12 20:19, Era Scarecrow wrote: I ask you, how do you check if it's a null pointer? &s? Yes, obviously. If you need to do that manually. But you shouldn't have to. int getx(ref S s) //How does this make sense?? it looks wrong and is misleading in {assert(&s); } body {return s.x); } It looks correct and is perfectly obvious. But see below - you don't need to do this manually - the compiler does it for you when calling methods and could handle the UFCS case too. How I'm understanding references in D (And perhaps I'm repeating myself in two different topics) is they point to live variables (IE guaranteed pointers), and remains this way until you return from that function. This is entirely valid and simplifies things. Remember in D we want the language to 'do the right thing', but if you make references where it works to 'sometimes works' then it becomes a problem (pointers 'sometimes' work and are not @safe, while ref is @safe). Checking the address of a reference shouldn't be needed, since it should be dereferenced at where it was called at if need be (throwing it there). Any side effects that may rely on the validity of the 'pointer' (once the function ends) are compromised afterwards (I'm always assume you pass local variables for this logic, since it's likely 80% of the time). Would you REALLY want to mark every single function that uses ref as @trusted? You're then blindly telling the compiler to 'shut up' so you can use the code and ignoring the checking; Or am I wrong? int getItem(string[] inp, string cmp) @safe { //foreach not @safe! //only works not @safe or blindly adding @trusted foreach(i, ref s; inp) { if (s == cmp) return i; } //still might not compile, if foreach calls opApply //(Even if it doesn't use the reference). foreach(i, s; inp) { } } More importantly, if it's now a possibility do we have to start adding checks everywhere? int getx(S *s) in {assert(s); } //perfectly acceptable check, we know it's a pointer body {return s.x); } struct S { int i; auto f() { return i; } } int main() { S* s; return s.f(); } This program will assert at runtime (and (correctly) segfault in a release-build). The compiler inserts not-null-this checks for "normal" methods in non-release mode, and could also do that before invoking any UFCS "method". So you wouldn't need to check for '!!&this' yourself. I thought those checks weren't added (via the compiler) since if it causes a seg fault the CPU would catch it and kill the program on it's own (just add debugging flags); If you added the checks they would do the same thing (More buck for the same bang). The problem w/ these checks is that they can not be disabled per-type - which prevents certain valid uses. The compiler-inserted assertions fire also when the methods can deal with null-this themselves (happens eg. when dealing with 'C' APIs and libraries, when you want to keep the C part as unmodified as possible). But that is a different issue.
Re: pointers, functions, and uniform call syntax
On Wednesday, 5 September 2012 at 11:01:50 UTC, Artur Skawina wrote: On 09/04/12 20:19, Era Scarecrow wrote: I ask you, how do you check if it's a null pointer? &s? Yes, obviously. If you need to do that manually. int getx(ref S s) //How does this make sense?? it looks wrong and is misleading in {assert(&s); } body {return s.x); } It looks correct and is perfectly obvious. But see below - you don't need to do this manually - the compiler does it for you when calling methods and could handle the UFCS case too. I've been thinking about this; It would definitely be the wrong thing to do. The assert would _Always_ succeed. The address you get would be of the pointer/reference for the stack (the pointer variable exists, where it points to isn't so much the case), so it would be the same as comparing it to this... int getx(S* s) in {assert(&s);} //always true, and always wrong. As I mentioned, it's wrong and is misleading. You'd have to work around the system to get the check correct; and even then if the compile decides to do something different you can only have it implementation dependent. int getx(ref S s) in { S *ptr = cast(S*) s; assert(ptr); } I'm not even sure this would even work (it's undefined afterall). I hope I never have to start adding such odd looking checks, else I would throw out ref and use pointers instead; At least with them the checks are straight-forward in comparison.
Re: pointers, functions, and uniform call syntax
On Thursday, 6 September 2012 at 10:29:17 UTC, Artur Skawina wrote: On 09/06/12 00:50, Era Scarecrow wrote: How I'm understanding references in D (And perhaps I'm repeating myself in two different topics) is they point to live variables (IE guaranteed pointers), and remains this way until you return from that function. The struct example I gave previously (quoted below) shows how easily you can end up with a null reference in D; refs are *not* guaranteed to be live. It's not just about pointers: class C { int i; auto f() { return i; } } int main() { C c; return c.f(); } Here you won't even get an assert error, just a segfault. But the pointer-to-class (reference type in general, but so far there are only classes) model chosen in D is wrong; this probably contributes to the confusion about refs, because they behave differently for classes. Let's ignore classes for now, they're "special". Yeah, they are allocated, and 'can' still contain a null reference (or be deallocated/voided) in some way, so are pointers automatically. Pointers *are* @safe, it's just certain operations on them that are not. To my understanding I thought pointers (almost everything of them) was not covered in SafeD/@safe code. True as long as you don't mess with the pointer, than the object could remain valid (assuming it was allocated), but you automatically go into low-level code, and in trusted or system programing. Would you REALLY want to mark every single function that uses ref as @trusted? No idea why you think that would be needed. Because we aren't allocating everything on the heap. Maybe I'm just seeing things at a very different angle than you. Maybe I need a core dump for my head. I've been thinking about this; It would definitely be the wrong thing to do. The assert would _Always_ succeed. The address you get would be of the pointer/reference for the stack (the pointer No, that's not how ref args work. '&s' will give you the address of the object (eg struct). A reference type like 'class' has another (internal) level of indirection so in that case you would get a pointer to the class-reference. But that's how classes work internally, the 'object' in that case is just the internal pointer to the "real" class data. Taking the address of an argument gives you a pointer to it in every case. Curious. Both ways could be correct. But somehow I don't think so... Alright let's go the opposite direction. Give me an example in which passing a variable (by reference to a function) would EVER require it to check the address to see if it was null. Class/allocated objects should fail before the function gets control. ie: void func(ref int i); class X { int i; } X x; int* i; int[10] a; func(x.i); /*should fail while dereferencing x to access i, so never gets to func*/ func(*i); //does this count as a lvalue? Probably not, func(a[0]);//none of these three should compile with that in mind func(0); Being named variables, and likely non-classes you are then left with mostly local variables, or arrays, or some type of pointer indirection issue. But ever case I come up with says it would fail before the function was called.
Re: pointers, functions, and uniform call syntax
On Thursday, 6 September 2012 at 12:00:05 UTC, Artur Skawina wrote: On 09/06/12 13:34, Era Scarecrow wrote: Alright let's go the opposite direction. Give me an example in which passing a variable (by reference to a function) would EVER require it to check the address to see if it was null. Class/allocated objects should fail before the function gets control. ie: void func(ref int i); class X { int i; } X x; int* i; int[10] a; func(x.i); /*should fail while dereferencing x to access i, so never gets to func*/ func(*i); //does this count as a lvalue? Probably not, func(a[0]);//none of these three should compile with that in mind func(0); Being named variables, and likely non-classes you are then left with mostly local variables, or arrays, or some type of pointer indirection issue. But ever case I come up with says it would fail before the function was called. Both '*i' and 'a[0]' count. (Even '0' could be made to work as a 'const ref' arg, but i'm not sure if that would be a good idea) I wasn't sure about *i. I can see it going either way. *i would need to be dereferenced first, a[0] would need a bounds check which then ensures it exists (even if it was dynamic); So checking an address from ref wouldn't be needed in the func.
Re: pointers, functions, and uniform call syntax
On Thursday, 6 September 2012 at 21:58:43 UTC, Artur Skawina wrote: This program won't assert and would segfault if 'i' was accessed by 'func'. So it seems. The way I read it says it dereferences it first. Regardless that you are forcibly referencing a pointer which is low-level trickery; which I'm sure is undefined behavior. Course if you have to check/treat it as a pointer, adding @safe suddenly refuses to compile (Won't let you get the address); But if you leave it out (without @trusted either) and make main @safe, suddenly that doesn't compile either. (Because I'm sure quite a few functions you'd want to share will end up being @safe and pure). auto func(ref int i) @safe { assert(!&i); //won't compile as @safe debug {//ignore that writeln is system writeln("Address:", &i); //here too writeln("Value:", i); } return i; } void main() @safe { int v = 100; func(v); int* i; func(*i); } As I commented before: Would you really want to blindly put @trusted on everything? In order for the above to work, either neither is @safe, or func is @trusted. Course you can always leave @safe out, assuming you aren't making anything you intend to share or will never be called by anything that's @safe.
Re: Is flags enum needed in Phobos?
On Wednesday, 26 September 2012 at 19:11:37 UTC, bearophile wrote: I think it's a good idea to have a well written EnumFlags data structure in Phobos. In C# this feature is even built-in. So issue 6946 is not closing, unless Andrei or Walter decide it's a bad idea to have something like this in Phobos. I've written one I believe if sufficient and am using in my current project. I'll add more to my branch as time goes on. https://github.com/rtcvb32/Side-Projects example in documentation [code] enum ETEST {none = 0, one = 1, two = 2, three = 3, four = 4} handle_flags!(ETEST, int) ftest; ftest.set_flag(ETEST.two);//check flag setting assert(ftest.state == 2); //int and enum compares. assert(ftest.state == ETEST.two); ftest.set_flag(ETEST.four); //set second flag assert(ftest.state == 6); //2+4, no 6 enum. //Flags can also encompass multiple bits. //in this case all bits returned with an //AND must match the flag. ftest.state = 1; assert(!ftest.checkAll(one, two, three)); //can't be true, only 1 is there ftest.state = 3; assert(ftest.checkAll(one, two, three)); //must be true, since 1+2 includes 3. [/code] Feel free to scrutinize and offer suggestions. Although it doesn't appear to be mentioned, you can also shorthand the flag with your alias. So ftest.one would be the same as ETEST.one or ftest.Enum.one. I recommend using with when you are using such flags.
Re: RFC: DConf 2013
On Wednesday, 3 October 2012 at 17:08:25 UTC, Andrei Alexandrescu wrote: I hear you. We have a detailed budget model and we're not splurging in any way. Organizing a conference has quite a few odds and ends and weird pricing. As an example, location providers offer good prices for the location proper BUT they require using their own catering services, which is how they make money. I co-organized a few conferences and, believe me, a cookie has a different taste when you know it was $5. That being said, if anyone on this forum works in the Bay Area and takes this to their employer, we'd save a ton of expenses if a company could offer a meeting room. I have initiated such with Facebook, and they're looking into it. All - please email me if such an opportunity exists. Depending on how many people would be attending, and I'm sure most of us are far enough away that a place to stay becomes a question. A quick glance suggests room swill be anywhere from $80-$200, and if it hits tourist season that number can double (or triple) easily. At some conventions you could get a discount if you mentioned you were part of the group, but if this group isn't large enough to warrant that kind of attention then perhaps something else. Perhaps at no cost find/contact a few hotels and that are willing to give discounts (aren't far from the site and reasonably priced) and list them as preferred options for lodging. Potentially also if a single hotel (or two) can reserve say a hundred rooms (or whatever is decided), a larger discount may be given especially for stays lasting multiple day. In that situation whoever is managing can collect the cost for the rooms (up front, say 3 months in advance). Regarding deposits I'm sure we would each handle our own. Also a thought. If the discounts are comparable enough compared to normally without this effort, then that discount can then be donated towards the conference and may build that up faster/easier.
Re: Is flags enum needed in Phobos?
On Sunday, 7 October 2012 at 09:22:17 UTC, Denis Shelomovskij wrote: I'd like to see enum syntax for flug enum. So I dislike function calls like `set_flag`, `checkAll`, etc. (IMHO) You mean... binary basic syntax? That shouldn't be too hard. So something like..? Flags x; with(Flags) { x += one; //setflag x -= two; //clearflag x ^= four;//flipflag x += [one,two]; //set flags multiple, same with flipping and clearing x -= [one,two]; x ^= [one,two]; //append ~ seemingly would be unused, or equal to + x = one; //reset completely to flag 'one' assert(x[one]); //checking, feels like an AA assert(!x[two]); x[two] = true; //optionally secondary way to set flag assert(x[one, two]); //only true if both are set. Flags y, z; z = x & y; //keep only flags within y z = x | y; //copy flags of both x & y z = x ^ y; //flip flags in x from y } This wouldn't be hard to add, but I was going for basic functionality, the extras are easy to use/add afterwards :) Probably for individual flags I'd use a template so when you optimize it will give you the smallest executing size for your results. Hmmm... The else is the only one I'm seeing a problem implementing easily, although using the built in types you can do it yourself. I'm not going to add odd binary operators if it doesn't make sense (Like shifting appending or slicing).
Re: Struct polymorphism?
On Sunday, 7 October 2012 at 10:04:57 UTC, Era Scarecrow wrote: 1) struct size can't size (no loss of data). 1) struct sizes and structures can't change (no loss of data)
Struct polymorphism?
What are the possibilities of struct polymorphism? What would be the issues with it? What if we wanted to use it in a limited sense? Currently I'm experimenting with it since classes are too bulky for what I need, yet I really need some type of behavior/dynamic polymorphism. So far I have a working model. It takes the following limitations: 1) struct size can't size (no loss of data). 2) every structure aside from the original needs a copy of the original (and only that) 3) original structure needs an enum specifying behavior mode 4) Template instantiation cannot be used (although automatic type deduction works). Using these and limiting it seems like it would sort of bring back C++'s design of classes, only better, simpler, and more powerful. It won't have an actual full virtual table as everything is known statically ahead of time, with only minor checks by opDispatch to determine which function set to run. Issues: 1) the base/original struct always calls it's own functions. A little work and I can probably remove that limitation, but the original struct would end up being only storage with no behavior at all. 2) Template instantiation. This is a limitation in opDispatch() where calling through it. As shows below. Maybe I'm just using opDispatch wrong. //signatures lacking structs auto ref opDispatch(string fun, Args ...)(auto ref Args args) @property; I templateType2(string val1, I)(I val); //call ps.templateType2!"Extra Extra!"(50); Error: ps.opDispatch!("templateType2") isn't a template Beyond this it seems to have some potential. Thoughts? Ideas?
Re: RFC: DConf 2013
On Sunday, 7 October 2012 at 15:20:44 UTC, Andrei Alexandrescu wrote: Seems like a big budget, what are the projected numbers? (10s? 100s? 1000s?) ;) The budget would cover around 55 attendees for 3 days. That includes (in decreasing order of cost) food, conference space, speaker support, A/V, staff remuneration, T-shirts/swag, and many smaller items.> Seems like a low number. I also assumed we would pack our own lunches, and food during the event would end up costing for 55 attendees is roughly $2000 (at least as an estimate). I figured the numbers would be closer to 200-300, but depending on how many speakers and how big the conference room... Just off hand I'm remembering that some hotels have a rentable room for conferences and meetings that may handle about 55 (Which sometimes is their continental breakfast area after the first thing in the morning), and assuming you wouldn't have a huge speaker system set up to disturb the normal customers in the lobby (assuming it's nearby) then in the case there isn't already a projector you can bring and set one up, although it wouldn't likely be too terribly big unless they have a blank white wall Mmmm... Having the meetings in the same hotel/motel you are staying it... Takes care of any commuting issue once you get settled in.
Re: Struct polymorphism?
Error: function expected before (), not 'this.polyBase.opDispatch!("orig")' I think this is a compiler bug. It complains about calling opDispatch, however it doesn't complain if you explicitly call 'this'. Should adding 'this' be required? I am using the -property switch so it's a little more strict, but that doesn't seem to change the results. I can't just start adding 'this' to all my function as outside normal functions/variables won't ever be seen. struct S { Something polyBase; alias polyBase this; //opDispatch string callsOrig() { return orig;//works but misleading return orig(); //breaks return orig(1); //breaks too return this.orig(); //works } } struct Something { auto ref opDispatch(string fun, Args ...)(auto ref Args args) @property; } My experiments concentrating on this part rather than with arguments, those will come later when this works.
Re: Will the D GC be awesome?
On Thursday, 4 October 2012 at 05:33:21 UTC, Walter Bright wrote: On 10/3/2012 2:26 PM, DypthroposTheImposter wrote: * OpCmp returning an int is fugly I r sad How else would you return a 3 state value? Via enums. enum CmpValues { lessThan = -1, equal = 0, greaterThan = 1} But then again, the enum is convertible to int :P. I think ints (or size_t) are just fine and do their job.
Re: Struct polymorphism?
On Sunday, 7 October 2012 at 10:04:57 UTC, Era Scarecrow wrote: What are the possibilities of struct polymorphism? What would be the issues with it? What if we wanted to use it in a limited sense? Currently I'm experimenting with it since classes are too bulky for what I need, yet I really need some type of behavior/dynamic polymorphism. So far I have a working model. It takes the following limitations: A question of efficiency comes up. If at compile-time we can confirm only a couple branches/possibilities, then only those are considered during run-time. During optimization is that code just inlined to where it is called rather than the jump to opDispatch? Seems like it should if it's small enough, especially if there's only 1 possibility. Now I guess a question out there for you all. Who would be interested in an implementation and how would you use it? Does it seem like a good idea? How many levels would you want to use? One? Several levels allowing class-like inheritance?
Re: Struct polymorphism?
On Tuesday, 9 October 2012 at 03:41:42 UTC, Era Scarecrow wrote: Now I guess a question out there for you all. Who would be interested in an implementation and how would you use it? Does it seem like a good idea? How many levels would you want to use? One? Several levels allowing class-like inheritance? Nothing yet it seems. Hmmm... Well I've thrown together a working version (in the last 4 days?) that needs more testing and documentation; But is a proof of concept, probably good enough for my other project. Incorporates a minimal encryption library for testing and demonstration. This makes heavy use of mixins. Thoughts and feedback are welcome. https://github.com/rtcvb32/Side-Projects
Re: What is the case against a struct post-blit default constructor?
On Friday, 12 October 2012 at 08:20:42 UTC, Jonathan M Davis wrote: Really, I think that it's a bad design decision to require that the invariant be called before opAssign. It does _not_ play nice with some of D's other features, and the result is likely to be that invariants get used less, meaning that code is more likely to be buggy. You make a good argument, but you can also override opAssign for things that are not it's type exact type. So... struct S { float x; ref S opAssign(int y) { x = y; return this; } } S s; int i; s = i; //opAssign, correct? In cases like this opAssign would need an invariant before and after the call. But if you were just replacing the whole object you wouldn't. I'll say a @novariant is the better answer, and automatically used on the default copy/opAssign/postblitz (before the call, but still needed after).
Re: Is flags enum needed in Phobos?
On Sunday, 7 October 2012 at 09:48:50 UTC, Era Scarecrow wrote: On Sunday, 7 October 2012 at 09:22:17 UTC, Denis Shelomovskij wrote: I'd like to see enum syntax for flug enum. So I dislike function calls like `set_flag`, `checkAll`, etc. (IMHO) You mean... binary basic syntax? That shouldn't be too hard. So something like..? Flags x; with(Flags) { x += one; //setflag x -= two; //clearflag x ^= four;//flipflag x += [one,two]; //set flags multiple, same with flipping and clearing x -= [one,two]; x ^= [one,two]; I've added binary functionality. Looking at these notes I see I forgot the enum/array part; And checking for binary true isn't added yet. However I'll get to it sooner or later. Both opBinary and opOpBinary are supported so far. x += one; //setflag x -= two; //clearflag x ^= four;//flipflag x &= two; //keeponly x |= two; //setFlag, same as += //should work fine, as with all operations, const/immutable safe. Flags y = x + one; if (x){} //compile error, will fix later if (x != Flags()){} //should work, compare against .init (probably 0) if (x.state){} //works but you shouldn't depend on this
Re: Is flags enum needed in Phobos?
On Sunday, 14 October 2012 at 06:34:39 UTC, Era Scarecrow wrote: I've added binary functionality. Looking at these notes I see I forgot the enum/array part; And checking for binary true isn't added yet. However I'll get to it sooner or later. Both opBinary and opOpBinary are supported so far. I can't get opOpAssign working properly, and it's worse with arrays. Removing opOpAssign, everything else (arrays, single flags, other flags) works properly. It's likely the last time I'll update it for a while. And I guess that's it.
Re: Is flags enum needed in Phobos?
On Monday, 15 October 2012 at 02:54:38 UTC, bearophile wrote: Era Scarecrow: I can't get opOpAssign working properly, and it's worse with arrays. Removing opOpAssign, everything else (arrays, single flags, other flags) works properly. Are such problems known? In bugzilla or here? Are those fixable? mmm... As I'm looking at it and making a reply, I've noticed a couple mistakes. Give me an hour or so to test and add it in. If all's well it will be fixed/added Are you going to create a Phobos GitHugHub pull request? Wasn't planning on it. If you feel the library is good enough, I may add a request. But more likely it will be merged with another file, likely std.bitmanip or something...
Re: Is flags enum needed in Phobos?
K I have opOpAssign working. I may have to clean up documentation a little and clean the unittests up a bit, but it all appears to be working. Feel free to give it a try. I have added opSlice, which returns an array of your enum of all the flags it qualifies for. An empty enum (say, zero) never qualifies as it has no bits to make it unique (or it would always be present no matter what). Mmm... I actually hope that's all that's needed for it.
Re: alias A = B; syntax
On Tuesday, 16 October 2012 at 07:52:51 UTC, Rob T wrote: alias int Int; Int x = 0; vs alias Int = int; Int x = 0; When I compare the two in this way, I'm inclined to keep things as they are. alias Int = int; this looks too much like variable declaration and instantiation, perhaps with only one it looks better to go this way. But what if you need several? Perhaps an unrealistic example, let's increase it by a factor of seven. alias SomeChar = char; alias SomeShort = short; alias SomeInt = int; alias SomeUInt = uint; alias SomeLong = long; alias SomeFloat = float; alias SomeDouble = double; uint MaybeBroken = nutmeg; const SomeChar FavoriateLanguage = 'D'; const SomeShort universeAndEverything = 42; const SomeInt hundredThousand = 100_000; const SomeUInt million = SomeInt * 10; const SomeLong largeNumber = SomeUInt * SomeUInt; const SomeFloat pi = 3.14; const SomeDouble pi2 = pi*pi; const MaybeBroken maybe= 2; or alias SomeChar = char; const SomeChar FavoriateLanguage = 'D'; alias SomeShort = short; const SomeShort universeAndEverything = 42; alias SomeInt = int; const SomeInt hundredThousand = 100_000; alias SomeUInt = uint; const SomeUInt million = SomeInt * 10; uint MaybeBroken = nutmeg; const MaybeBroken maybeBroke = 2; alias SomeLong = long; const SomeLong largeNumber = SomeUInt * SomeUInt; alias SomeFloat = float; const SomeFloat pi = 3.14; alias SomeDouble = double; const SomeDouble pi2 = pi*pi; vs alias char SomeChar; alias short SomeShort; alias int SomeInt; alias uint SomeUInt; alias long SomeLong; alias float SomeFloat; alias double SomeDouble; alias nutmeg MaybeBroken; const SomeChar FavoriateLanguage = 'D'; const SomeShort universeAndEverything = 42; const SomeInt hundredThousand = 100_000; const SomeUInt million = SomeInt * 10; const SomeLong largeNumber = SomeUInt * SomeUInt; const SomeFloat pi = 3.14; const SomeDouble pi2 = pi*pi; const MaybeBroken maybeBroken = 2; or alias char SomeChar; const SomeChar FavoriateLanguage = 'D'; alias short SomeShort; const SomeShort universeAndEverything = 42; alias int SomeInt; const SomeInt hundredThousand = 100_000; alias nutmeg MaybeBroken; const MaybeBroken maybeBroken = 2; alias uint SomeUInt; const SomeUInt million = SomeInt * 10; alias long SomeLong; const SomeLong largeNumber = SomeUInt * SomeUInt; alias float SomeFloat; const SomeFloat pi = 3.14; alias double SomeDouble; const SomeDouble pi2 = pi*pi; Without the assignment operator it stands out a little more of it's intention and not a variable declaration. But honestly both work, I wouldn't mind having the alternate syntax (as long as the language doesn't clutter and break anything).
Re: Tricky semantics of ranges & potentially numerous Phobos bugs
On Tuesday, 16 October 2012 at 17:06:06 UTC, Jonathan M Davis wrote: There's also no way to validate that front always returns the same value, or that popFront actually pops a value, or that it pops only one value, etc. Pretty much _all_ that we can verify with template constraints is function signatures. So, we can _never_ fully restrict range types to exactly what would be considered correct. An option that may be decided on, is if an enum is used to specify certain behavior decisions made by the programmer, then only a few new templates to check for those and return true when those are specifically true. Perhaps an example to use? enum RangeTypes { normal, mutating, popDisgarded, ... } template isRangeMutating(T) if (hasMember!(T, "rangeType")) { enum isRangeMutating = T.rangeType == RangeType.mutating; } //function that cannot accept input range that mutates any members due to //popFront/popBack void something(I)(I input) if (isInputRange!(I) && (!isRangeMutating!(I))) { /*...*/ }
Re: D seems interesting, but...
On Monday, 15 October 2012 at 14:29:42 UTC, foobar wrote: Java has the correct DRY solution - each class can define a static main method but the compiler only uses the one specified by a compiler switch. The above basically asks the programmer to endlessly repeat the same trivial implementation boilerplate that should be written just once _in_ the compiler. I remember this. I remember scratching my head and asking why, but then realizing that likely 99% of the time it's never called, so I started using it to build and do unittests (without Junit). Curiously. I'm suddenly reminded of a test suite I made for a company for Visual Basic. It was years ago and a nice little test suite; I really wish I had a copy.
Re: Array of structs construction
On Saturday, 20 October 2012 at 01:06:57 UTC, bearophile wrote: I'd like to write code like this (the constructors of the structs must take 1 argument): // some imports here void main() { BigInt[] data1 = [5, 6, 9]; Ranged!(int,5,10)[] data2 = [5, 6, 9]; Nibble[] data3 = [1, 2, 15]; // Nibble.sizeof == 1 alias Typedef!int Mint; Mint[] data4 = [5, 6, 9]; } Do you like this feature? Currently in D you write this, it's not handy if you have many items: // some imports here void main() { auto data1 = [BigInt(5), BigInt(6), BigInt(9)]; alias Ranged!(int,5,10) R; // a short name auto data2 = [R(5), R(6), R(9)]; auto data3 = [Nibble(1), Nibble(2), Nibble(15)]; alias Typedef!int Mint; Mint[] data4 = [Mint(5), Mint(6), Mint(9)]; } Only way i can see this working simply, is if it's auto, at least one of the items have to specify it's full type and the rest can be ignored. Also it must have a constructor that takes that one type of argument. So.. //50 & 100 aren't BigInt, but can be constructed to be one.. auto bignums = [BigInt(25), 50, 100]; As for above arrays where the type is known, I can't see a reason why it can't work. In a large array of static data I've had to make shortcut names for several structs in order to keep it readable and programmable. This may help in some cases, or perhaps all of them. Course this also means if a structure is being initialized then perhaps it can be extended. Like the above, except... struct S { int x,y; BigInt z; } S s = {1,2,3}; //3 converted if BigInt has a constructor for int //if that's illegal, then you'd do this to make it work instead, //which seems... unnecessary. struct S { int x,y; BigInt[1] z; } S s = {1,2,[3]}; The downside is if there's memory allocation or heavy work that can't be done at compile-time then there may be more complex issues trying to optimize something. Makes it sorta mixed.
Re: [RFC] ColorD
On Sunday, 21 October 2012 at 19:28:21 UTC, Robik wrote: I would like to introduce ColorD, small library that allows to simply manipulate console output colors, both on Windows and Posix operating systems. It also supports font styles such as underline and strikethrough(Posix feature only). Does this rely on nCurses? (or similar)
Re: DConf 2013 on kickstarter.com: we're live!
On Monday, 22 October 2012 at 18:49:22 UTC, Andrei Alexandrescu wrote: On 10/22/12 2:32 PM, mist wrote: There is a serious reason of getting through some registration issues and pledging via kickstarter - project either gets all money if it is funded or no at all if it is not (and all pledges are returned automatically). And, of course, any other means of supporting won't be counted by kickstarter towards target sum. Yes, this. If we don't break through the limit, nobody is charged a dime. It would be more complicated to refund checks etc. I happened to have a facebook (alternate sign-in) & amazon accounts so it was fairly quick and painless for me. I'll look forward to the results of the kickstarter.
Re: DConf 2013 on kickstarter.com: we're live!
On Monday, 22 October 2012 at 23:37:25 UTC, Tyro[17] wrote: Yes, this. If we don't break through the limit, nobody is charged a dime. It would be more complicated to refund checks etc. So let's see to it that it does break through that limit!!! Already within a day and it's about 25% there. Looks promising.
Re: DConf 2013 on kickstarter.com: we're live!
On Tuesday, 23 October 2012 at 11:46:11 UTC, Iain Buclaw wrote: On 23 October 2012 12:34, jerro wrote: Perhaps FSF would help or some other open-source funding organisation? Wouldn't FSF have issues with the reference implementation's back end not being free software? We aren't celebrating dmd here, we are celebrating the D programming language, which is a F/OSS project. I don't think FSF would be that picky. As Iain said, it's about the D language which is an open spec, and progress in the community as a whole. Afterall, if we were getting together to talk about AWK, they may contribute even considering a free version (Gawk) is available, and it isn't about which version you run at all. But the spec not being ANSI managed may provide some problems. I may get this wrong, but my understanding FSF's view (and spirit thereof) is about keeping the freedom; IE: Learning from eachother (be it mistakes or otherwise), enable the willingness to fix (or offer fixes), and allow you to improve any given piece of software with no personal or financial gain from it, out of only the love and want to help the community as a whole.
Re: Passing static arrays to C
On Wednesday, 24 October 2012 at 09:16:30 UTC, Walter Bright wrote: C accepts static arrays as pointers, so T[n] in D would be C prototyped as T*. Pass a pointer to the first element. In GCC (or any c compiler) isn't it possible in optimizing to copy the static array to the stack (say 8 bytes or less as a guess)? Course this assumes the static size is set as part of the function signature too... It makes sense for it to work both ways (in their own way); But then more bugs can lie in wait as well.
Re: Why D is annoying =P
On Wednesday, 24 October 2012 at 19:41:42 UTC, Mehrdad wrote: So you can't really write a real program in D, to put it blunty. So should I drop a project I'm working on and go to C++? That isn't something I look forward to doing...
Re: Why D is annoying =P
On Thursday, 25 October 2012 at 00:53:31 UTC, Mehrdad wrote: On Wednesday, 24 October 2012 at 21:55:53 UTC, Era Scarecrow So should I drop a project I'm working on and go to C++? That isn't something I look forward to doing... Well if it's been working for you then there's obviously no reason to. :) I couldn't say the same thing, though. You can always work around what does and doesn't work; Although preferably you shouldn't have to. I can only think that the best way to support the D language is simply to use it. If there's several programs that really get attention that shows the flexibility and use of D then it's more likely to be used. My biggest obstacle(s) right now is time & memory. With new issues coming up it makes you think in different directions, which all makes sense once you look for them.
Re: Why D is annoying =P
On Thursday, 25 October 2012 at 01:50:05 UTC, Mehrdad wrote: Well I mean, yeah, you can obviously implement your own data structures, and eventually, your own version of Phobos, even. The trouble is, then you're fighting the framework, and nothing integrates with anything else. Some data structure expects a toHash() instance method, another expects .hashOf, another getHash(), another getHashCode(), another might say hashCode(), and yet another might just expect a template specialization, like in C++. So the point is, yes, it's possible. It's not that I can't work around it, but it defeats the whole purpose of switching to D. I have no intention of writing a different version of phobos or breaking the framework. I'll work within the framework as much as possible; Working around the issues usually ends up force casting something so you can get the job done (but you still need to honor the type's original contract). I'll just hope my data processing won't require anything that's broken or going to be depreciated, I've already dropped using std.stream for ranges instead. Dropping classes in favor of structs.
Re: Why D is annoying =P
On Thursday, 25 October 2012 at 02:19:39 UTC, H. S. Teoh wrote: Huh? Why would you drop classes in favor of structs? They are used for two different purposes. Classes are for when you need polymorphism: inheritance, overloading, interfaces, all the trappings of OO programming. Structs are for when you need value types that doesn't need OO-style manipulations. Not the same thing. Indeed. Instead of interfaces you'd use templates, OO doesn't change really all that much. There's also large amounts of memory consumption that just isn't needed for data that hasn't and/or isn't going to change. More often I'm thinking structs w/templates are more powerful than classes. I'm experimenting with a polymorphic struct. Run-time price is a couple enum checks if there's multiple functions that might qualify, and slightly different calling for those polymorphic types.
Re: assert(false, "...") doesn't terminate program?!
On Saturday, 27 October 2012 at 18:36:57 UTC, H. S. Teoh wrote: On Sat, Oct 27, 2012 at 08:26:21PM +0200, Andrej Mitrovic wrote: Maybe related to -release? Haha, you're right, the assert is compiled out because of -release. Then it is a bug; Unless perhaps it is inside a contract (in/out) or debug statement. TDPL pg 326: [quote] An assertion against a constant that is known to be zero during compilation, such as assert(false), assert(0), or assert(null), behaves a tad differently from a regular assert. In non-release mode, assert(false) does not do anything special: It just throws an AssertError exception. In release mode, however, assert(false) is NOT compiled out of existence; it will always cause a program to stop. This time, however, there would be no exception and no chance of continuing to run after an assert(false) was hit. The program will CRASH. [/quote]
Re: assert(false, "...") doesn't terminate program?!
On Saturday, 27 October 2012 at 19:08:02 UTC, H. S. Teoh wrote: No it's not a bug, because the value is *not* known to be zero at compile-time (it depends on what value you put in the BigInt). I think I read the question wrong earlier. My apologies.
Re: Why D is annoying =P
On Monday, 29 October 2012 at 05:43:43 UTC, H. S. Teoh wrote: On Mon, Oct 29, 2012 at 01:28:51AM -0400, Nick Sabalausky wrote: Did someone say "PHP"? ;) I thought I heard "Javascript"... :-P Both seem to have their own issues, although I'd say javascript is worse than PHP. (at least PHP runs on the server).
Re: Decimal Floating Point types.
On Monday, 29 October 2012 at 22:49:16 UTC, H. S. Teoh wrote: I thought it was better to use fixed-point with currency? Or at least, so I've heard. Depends on the application. Years ago (10?) I made a little interest calculating C program, floating point and rounding gave me so many issues with 1-2 pennies off that I went with an int and just took the bottom 2 digits as pennies. Worked far better than fighting with the floating point issues. I do remember somewhere that the double could be used to accurately calculate money up to 18 digits, but I can't remember if there was a specific mode you had to tell the FPU.
Re: What is the use case for this weird switch mecanism
On Tuesday, 30 October 2012 at 21:11:57 UTC, bearophile wrote: Nick Sabalausky: Obfuscated coding contests? It's there to help programmers create more bugs, of course :o) Maybe variable declaration (as long as they are default(s))? Has a certain amount of sense, but makes more sense to do it outside the switch case...
Re: What is the use case for this weird switch mecanism
On Tuesday, 30 October 2012 at 21:40:26 UTC, bearophile wrote: Era Scarecrow: Maybe variable declaration (as long as they are default(s))? Declaring variables there is dangerous: switch(bar) { Foo f; case 10: break; default: writeln(f); // prints garbage } Then it's as though it were '= void;' by default. Most curious. Honestly I'd say it's illegal to have something before any callable case; Besides for goto's it's illegal to jump past declarations, yet this switch case allows it. I'd say one of two things must happen then. 1) Code before the first case is disallowed 2) Code before the first case always runs Option 2 seems silly and unneeded, except it allows a small scope during the switch call, which is it's only possible advantage. The only other advantage is you could have a case disabled and enable it during certain debugging cases, but in those cases why not do the whole block? switch(bar) { static if (DEBUG) { case -10: /*disabled case, or something like that*/ } Foo f; case 10: break;
Re: What is the use case for this weird switch mecanism
On Wednesday, 31 October 2012 at 22:01:36 UTC, bearophile wrote: Chris Nicholson-Sauls: There is also the trick of doing 'switch(val) with(EnumType) {...}' What about writing with(EnumType) switch(val) {...} ? Maybe... But a problem arises when it's function wide, and should be able to replace (hopefully) any block. Assuming there's no syntactical issues that may break other code. int func() with(EnumType) { //won't compile } int func() { with(EnumType) { //compiles but seems excessive when it doesn't need to... } } But 'switch with' seems the proper way to put it in my mind.
Re: What is the use case for this weird switch mecanism
On Wednesday, 31 October 2012 at 22:58:32 UTC, bearophile wrote: Era Scarecrow: But 'switch with' seems the proper way to put it in my mind. It's not worth the unsafety of the whole switch. What? I'd need a little explanation what you'd mean. besides, 'switch with' and 'with switch' are practically identical... aren't they?
Re: DConf 2013 on kickstarter.com: we're live!
On Thursday, 1 November 2012 at 19:35:35 UTC, Jacob Carlborg wrote: On 2012-11-01 20:18, Andrei Alexandrescu wrote: Hoping is good, making it happen is even better. Does anyone have the equipment and expertise to help with video recording? Funny thing. Most video clips from conferences I've seen are fairly poor quality. I don't know if it's the recording or the compression after it been uploaded. But these days many phones have pretty good cameras, like 1080p. I have some expertise & some equipment; But I plan on getting more shortly anyways (and could run it too). Something to consider is encoding the videos and could ship them on dvd/blueray. Hmmm, with dvd it would have to be avi/mkv's while on blueray if the options allow could use the player rather than having a computer file format, then it's only a matter of time before I can have them all burned. On the other hand, if we have something like 1000 people wanting discs, it might be possible to have them made once we make the original (course the minimum may be 50,000 which wouldn't be an option at this time). But if we consider almost everyone has the internet and youtube is available and allows HD and long submissions for this type of stuff that quickly seems like a silly option.
Re: D vs C++11
On Friday, 2 November 2012 at 22:02:04 UTC, Nick Sabalausky wrote: So whenever D is a viable option, I always go for it because I find it to be vastly superior, even to C++11 (which is merely "slightly less crappy than old C++", IMO). And then when I *have* to use C++, I do so while wishing I was doing it in D. I remember trying to read and learn C++ years and years ago. Got a headache just trying to read & understand it (2005ish). It felt like it wasn't consistent with C, it was ugly, friend functions never quite made sense, the default 'streams' library should have been written differently (It was originally an example class correct?) Let's see what else. Headers, document twice, virtual has to be explicitly declared so inheritance is more limited. Constructors had to be the same name as the class, just a bunch of things that didn't quite seem like they fit right. Reading/learning how the STL works they based everything off pointers (which makes some sense) but rather than make a new type and work on that they tried to make that backwards compatible with C, so to use iterators you simulate a pointer. I can understand it's limitations on systems back when memory and drive space was scarce, but we're way past that now. "Polish a turd, it's still a turd!" -- Peanut
Re: 'with' bug?
On Saturday, 3 November 2012 at 20:29:14 UTC, bearophile wrote: Faux Amis: Care to elaborate on that? They share most of the problems of global variables. While not evil, it's better to avoid module-level mutables. This makes the code more testable, simpler to understand, less bug prone, and makes functions more usable for other purposes. In D there the attribute "pure" is present also to enforce such better coding style. Let's not forget that since global variables are 'per thread' that the issues involving them lessen and are less evil than before.
Re: Transience of .front in input vs. forward ranges
On Saturday, 3 November 2012 at 23:19:11 UTC, H. S. Teoh wrote: I wish Andrei would give some input as to how we should proceed with this. I do consider this a major issue with ranges, because for efficiency reasons I often write ranges that have transient .front values, and they can lead to subtle bugs with the current implementation of std.algorithm. It would be good to settle on this issue one way or another. I'd be happy even if the decision is to say that transient ranges are invalid and shouldn't be considered "real" ranges. Anything is better than the current nebulous state of things which only leads to subtle bugs for the unwary. From watching and gleaming from what I have so far, I can only think that transient should NOT be the default way that ranges work (as it causes too many problems); However transient should be allowed (and available) when possible. I can only think that perhaps using a template to determine if it's transient should be present, that way it's a simple flag to enable/disable and should propagate anywhere that that range was used. struct Range(bool isTransient=false) { static if (isTransient) { //front and transient } else { //front and non-transient } } Unless someone thinks this is a bad approach?
Re: I challenge "D"
On Sunday, 4 November 2012 at 07:23:51 UTC, Job wrote: And all will see after Tuesday (save for Al Queda or other messing up your plan of world domination). Is it possible to have admins remove topics? Or better yet, anyone can flag it and then the admin can confirm it and it goes away? Or the admins can Mark him as a spam bot? I remember someone (a bot?) doing this something like 6 months ago (and looks like the same topics too).
Re: I challenge "D"
On Sunday, 4 November 2012 at 09:23:14 UTC, Maxim Fomin wrote: Possible but AFAIK unfortunately nobody is doing this. I have never encountered a crazy topic been deleted. Mmm I've wondered too.. there's cases where new topics are made by accident (reply via email, and other cases) where it should instead be attached to a particular spot in another topic. I don't see why access can't be granted to a few dozen who are commonly present to be able to move/attach those topics. Course if you can do that, you can throw all the spam on a single topic and everyone will know to ignore it. Oh well.. Don't feed the trolls...
Re: Why does std.variant not have a tag?
On Sunday, 4 November 2012 at 22:31:56 UTC, evansl wrote: Yet, the wiki page: http://en.wikipedia.org/wiki/Tagged_union says: a tag field explicitly indicates which one is in use. and I don't see any indication of a tag field in the std_variant.html I remember a while back asking about the variant. I wanted to be able to specify an area in memory and say 'this is xxx', but couldn't; This was to help avoid having to manually make and manage something like 60 structs and far more complex code to manage that. This leads me to develop my own version (for built-in types); My version isn't anywhere complete (or clean enough) for publication, but enough for my own project (as read-only use). Hmmm curiously enough, i might be able to convert/rebuild by using a polymorphic struct that I'm tinkering with, but that seems like a lot of extra work.
Re: Const ref and rvalues again...
On Wednesday, 7 November 2012 at 00:32:04 UTC, martin wrote: So we do not really need 'auto ref' for non-templated functions or a new, even more confusing keyword which you, Jonathan, seem to insist on - 'const ref' (or, more elegantly 'in ref') is all we need. We simply want the compiler to automatically declare rvalues passed to 'const ref' parameters as local lvalues - problem solved for the majority of cases. For the remaining few which care about the involved cost for rvalue arguments, allow them to provide a function overload for rvalues (either manually or via 'auto ref' templates) - problem solved completely in my point of view. And that is actually exactly what the thread starter Malte proposes (and I already pointed that out in an earlier post). 'in ref' may work, but what it implies doesn't quite make sense. 'auto ref' already being used for templates should be able to carry over to functions, however auto in the same section along with type declaration may seem a little confusing. Let's glance at a few of how they would be called. //either void func(int x); void func(const int x); //lvalue void func(ref int x); void func(const ref int x); //either? auto ref/in ref void func(auto ref int x); void func(const auto ref int x); void func(in ref int x); Assuming auto can't be used to do type referencing the 'const auto ref int' seems rather long. alternatively perhaps inout? (accepts any type, partially skewed?) void func(inout ref int x); void func(const inout ref int x); At this point for const it's just as large as the const auto ref.. So.. void func(inout ref int x); //mutable void func(in ref int x);//const version void func(out ref int x); //optional write-only variable 'out ref int x' could then be legal.. Somehow reminds me of zlib's compress utility function that returns how many bytes the output buffer used but sometimes you didn't care. So.. if we defined and used... void func(out ref int x) { x = 100; } int x; func(x); assert(x == 100); func(0);//0 and null (and legal) basically ignored. func(null);
Re: Const ref and rvalues again...
On Wednesday, 7 November 2012 at 02:45:15 UTC, martin wrote: Please discard option 1, I'm afraid it creates too much confusion and was not well thought through. The objective was to expand 'auto ref T' to either 'in ref T' for lvalues or 'in T' for rvalues (I.e., only for const parameters!), but then its caption would be horribly misleading (and something like 'in auto ref' would be way too ambiguous). Maybe a very simple change/addition; Like perhaps @ref? (Attribute ref, Alternate ref, auto ref.. All sorta fit for it's meaning). So... void func1(ref int x); //D lvalue-only ref void func2(@ref int x); //works like c++'s ref Seems fairly easy to tell apart, and still leaves const-ness as an option.
Re: Const ref and rvalues again...
On Wednesday, 7 November 2012 at 03:13:22 UTC, martin wrote: void func1(ref int x); //D lvalue-only ref void func2(@ref int x); //works like c++'s ref Seems fairly easy to tell apart, and still leaves const-ness as an option. Afaik C++ doesn't allow rvalues to be passed to _mutable_ references (T&), only to const references, making perfect sense imo. I really do not see the point for an additional syntax for C++-like const references (const T&) which would also take rvalues. Please give me an example where you want to pass an rvalue to a _mutable_ reference parameter. I would simply continue to disallow that, since that would mean that changes to the referenced rvalue would not be visible for the caller (a temporary/literal is changed - how could someone possibly want that?). Still that zlib entry is coming to mind. But more importantly is that you still need code duplication to get both accessible. //many possible combinations thereof int func(const ref x); int func(int x) { return func(cast(const int) x); } But regarding zlib.. It's function is something like: int compress(char *output, int *size, char *input, int inputSize); So... if we convert that to something similar we get.. enum ZlibEnum {} ZlibEnum compress(void[] output, void[] input, &ref Zlib state) nothrow pure; The idea in this case is 'state' would continue to hold the input/output pointers and all information needed, so you could continue to use it and if it has any 'unflushed' data (output size too small?) then it could retain that. however if you knew you didn't need it you could ignore it. ZlibEnum could be for output C calling code, so success/failure needs to be known right away. It makes sense for it to return a Zlib type as well, but depends on what has higher priority and why. string input = "something long"; ubyte[1000] output; ubyte[5] output2; Zlib state; compress(output, input, null); //we know the buffer is large enough compress(output, input, state);
Re: Const ref and rvalues again...
On Wednesday, 7 November 2012 at 03:13:22 UTC, martin wrote: void func1(ref int x); //D lvalue-only ref void func2(@ref int x); //works like c++'s ref Seems fairly easy to tell apart, and still leaves const-ness as an option. Afaik C++ doesn't allow rvalues to be passed to _mutable_ references (T&), only to const references, making perfect sense imo. I really do not see the point for an additional syntax for C++-like const references (const T&) which would also take rvalues. Please give me an example where you want to pass an rvalue to a _mutable_ reference parameter. I would simply continue to disallow that, since that would mean that changes to the referenced rvalue would not be visible for the caller (a temporary/literal is changed - how could someone possibly want that?). Still that zlib entry is coming to mind. But more importantly is that you still need code duplication to get both accessible. //many possible combinations thereof int func(const ref x); int func(int x) { return func(cast(const int) x); } But regarding zlib.. It's function is something like: int compress(char *output, int *size, char *input, int inputSize); So... if we convert that to something similar we get.. enum ZlibEnum {} ZlibEnum compress(void[] output, void[] input, &ref Zlib state) nothrow pure; The idea in this case is 'state' would continue to hold the input/output pointers and all information needed, so you could continue to use it and if it has any 'unflushed' data (output size too small?) then it could retain that. however if you knew you didn't need it you could ignore it. ZlibEnum could be for output C calling code, so success/failure needs to be known right away. It makes sense for it to return a Zlib type as well, but depends on what has higher priority and why. string input = "something long"; ubyte[1000] output; ubyte[5] output2; Zlib state; compress(output, input, null); //we know the buffer is large enough compress(output2, input, state);
Re: Const ref and rvalues again...
On Wednesday, 7 November 2012 at 04:05:32 UTC, martin wrote: int func(in ref int x); int func(int x) { return func(x); } The latter overload is for rvalues (no need to cast to const) and wouldn't be required if the first one took rvalues directly (having a _const_ ref parameter). That's not an example for mutable references though, it's basically a shortcut so as to not having to declare all rvalues for x manually. Maybe... But when working with non built-in types can you guarantee that behavior? //same as 'const ref' basically, unless 'in ref' is accepted struct S //int func(in ref S x); //? int func(const ref S x); int func(S x) { return func(x); } //potentially infinitely self calling compress(output, input, null); compress(output2, input, state); Where's the rvalue? You're talking about an optional mutable reference here, which is only doable via a pointer (references cannot be null, not in C++ and not in D): Perhaps null is wrong in this case, but had it been Zlib.init or Zlib(), then it would still be applicable. Since it's a reference I would think it could accept a null pointer and realize to create a temporary which has it's default values. That would be correct. But you're completely missing the point here. Let's assume you wanted to require a state to be passed: ZlibEnum compress(void[] output, void[] input, ref Zlib state); You could now use: Zlib state; // lvalue compress(output, input, state); but not: compress(output, input, Zlib()); // rvalue And that is most likely a good thing, since your state would be lost after the compress() call. If you don't want it, you don't pass it, and as I said, the only way to do that is to pass a nullable pointer. So this is off-topic I'm afraid. True, but rather than having to create a temporary you don't plan on using just to satisfy the signature, and you know you don't NEED it afterwards, why do you have to go through the extra steps? How many wrappers are made in general just to work around minor issues like this? Quite often we ignore return types if they aren't interesting, but we can't ignore a rvalue we only need for one call (or just to satisfy the signature)? Say we have a divide function (who knows what for), and this is more efficient than normal. So... //perhaps '@ref int remainder = 0'? int divide(int number, int divisor, ref int remainder); Now in this case what if we don't care about the remainder? Create a temporary (or a wrapper function)? //satisfy remainder int divide(int number, int divisor) { int tmp; return divide(number, divisor, tmp); } int modulus(int number, int divisor) { int tmp; divide(number, divisor, tmp); return tmp; } But if we want the result of the division AND the remainder should we have to make a separate modulus function when the original divide can clearly give you the answer? This cuts closer to the instruction set as an example.
Re: Const ref and rvalues again...
On Wednesday, 7 November 2012 at 10:33:03 UTC, Timon Gehr wrote: You are still missing that const in C++ is different from const in D. Also, if the point is to have higher speed, why shouldn't the function be allowed to use an rvalue as scratch space without a _deep copy_ ? const in C++ does not mean anything. It is just loosely enforced interface documentation. const in D actually restricts what the callee can do with the argument, in a transitive fashion. Also depending on how you think of it, the const ref in C++ logically it didn't make sense to pass a mutable rvalue; Say you pass the number 3, you can't modify it logically (ie you can't redefine PI afterall). When my struct does not support any operations that are const, and creating a mutable copy is not possible due to indirections? I would simply continue to disallow that, since that would mean that changes to the referenced rvalue would not be visible for the caller (a temporary/literal is changed - how could someone possibly want that?). The change may well be visible... class C{ int x; } struct W{ C c; } W createW(C c){ return W(c); } void foo(ref W w){ w.c.x = 2; } void main(){ C c = new C; assert(c.x==0); foo(createW(c)); assert(c.x==2); } So basically being named (or not) doesn't change the data, what it is or how it's used, only how accessible it is. There's some forms of techniques that don't seem to have any value until you have a chance to think about it and use them; Like scopes, overloading, referencing, Exceptions you can easily do without them all (We have C afterall), but it isn't as much fun or clean. Some features and uses thereof make more sense for the back/private implementation rather than the public interface. The reason I gave my 'divide' example is because a while back I wrote a BitInt (in C like 10 years ago, and a bit buggy); The divide function actually calculated the remainder as a side effect, and using wrappers or writing them as separate portions would actually be harder and slower than joined as it was.
Re: DConf 2013 to be recorded
On Wednesday, 7 November 2012 at 21:38:58 UTC, Nick Sabalausky wrote: On Tue, 06 Nov 2012 07:11:19 -0800 Walter Bright wrote: That'd work fine. It doesn't need to be 320 bit quality! Yup, AIUI mp3 was designed for voice anyway, that's why music needs to be cranked up to ridiculous bitrates to not sound shitty when you're using mp3 instead of a proper general-purpose audio codec like vorbis or aac. Both Vorbis and MP3 can be set as VBR (Variable Bit Rate), however I would think that's post processing; If possible I would think you get as high of quality as you can reasonably get, then downgrade it afterwards. If you got 50Gb of space for audio, why not record at 320kbits? Thank heavens for MPEG-4 (and AVC/h.264), otherwise video would still be difficult to transmit over the internet at decent speeds. If I attend and that's very likely (unless something huge happens... like my death...) then I would bring an external drive or two, meaning drive space during the recording and time there wouldn't be an issue; Although having a backup in case one of the drives fails seems important at that point (losing the only copy would be quite annoying to everyone).
Re: Getting rid of dynamic polymorphism and classes
On Thursday, 8 November 2012 at 17:27:42 UTC, Tommi wrote: I just started watching that: http://cppnow.org/session/value-semantics-and-concepts-based-polymorphism/ I've ripped the audio and done some processing to make it a little more understandable (without cranking the audio up to god awful levels); however I seem to have a little trouble uploading it somewhere accessible. I'll post a link when I get it uploaded (assuming anyone wants to make use of the audio rip...)
Re: Getting rid of dynamic polymorphism and classes
On Friday, 9 November 2012 at 21:06:16 UTC, Ziad Hatahet wrote: Method dispatch is still done at runtime though. If opDispatch is small&simple can/does it get inlined to the callers?
Re: Getting rid of dynamic polymorphism and classes
On Friday, 9 November 2012 at 21:52:49 UTC, Iain Buclaw wrote: On 9 November 2012 21:39, Era Scarecrow wrote: If opDispatch is small&simple can/does it get inlined to the callers? Potentially yes, but only with optimization turned on. ;-) I thought so, and hope so :)
Re: "Dads" with tapped bitches
On Saturday, 10 November 2012 at 05:09:43 UTC, Rob T wrote: There's several posts in a row like it. All from Job no less...
Re: Const ref and rvalues again...
On Tuesday, 13 November 2012 at 08:34:19 UTC, luka8088 wrote: Would it ? How many functions actually change their non ref/out arguments ? Can you point out any existing public code that would be broken ? It would be possible that if the language became const-preference that a simple regex tool could be made that would do the conversions, thereby any code broken in this way could be un-broken just as easily; But that assumes you aren't using mixins or magic as part of your signatures. Somehow this reminds me a little of when I worked at a company where we were trying out asp as a web server; The whole VB script was by default 'by ref' so you littered all your functions with 'byVal' in order for your behavior to act as you expected. Anyways, my take on this is consistency would be a lot more difficult and annoying unless you had different rules for the signature vs all other references... I doubt you would say 'this is mutable here but immutable here' type of thing. So assuming 'mutable' is used, then the following would be comparable... //D as of now int func(int x, int y, const ref int z) { int something; //mutable far more likely int something2; const int lessOften; } //then would become... //if x & y aren't ever changed then mutable may be unneeded. mutable int func(mutable int x, mutable int y, ref int z) { mutable int something; mutable int something2; int lessOften; //const (once set) } //or for inconsistancy.. //mutable or const as a return? (Or either?) //and which would/should you use to reverse it? int func(mutable int x, mutable int y, ref int z) { int something; //mutable int something2; const int lessOften; //const } Seems in a function body you are far more likely to have mutable items, while in the signature you're more likely to have const items; But mixing them or changing how you do it would likely break code very easily if it isn't signature only, but it doesn't seem like a good idea... Now in the above the function may not specify 'x' is const it doesn't guarantees it ever changes it (but it's a local copy so does it matter?), but specifically specifying it may be more clutter than actually useful. All in all it seems like it would have far more confusion (and break code) than help; although having it prefer const versions of functions/methods to non-const ones should probably have a higher priority (Although you then couldn't have a non-const one unless it was as part of the struct/class constness and not the variables, (and ref preferred over non-ref)).
Re: Const ref and rvalues again...
On Tuesday, 13 November 2012 at 10:09:27 UTC, luka8088 wrote: Can you point out any existing public code that would be broken? Off hand, no.. I'm not that familiar with a lot of the code or the in depth details of phoboes; However suddenly reversing what is mutable and what is const is bound to break a lot of things even unintentionally. Hmmm.. Does remind me of a bit of my code sometimes... Something went like... class S { void func(S s) { if (!s) s = new S(); //create one if not passed in. //process using S and s (be it new or passed in) } } That would certainly cause a problem.. In my own code example it may empty the pointer/reference if certain requirements were met, and then use if the class reference was set or null for later logic (even if the object referenced to wasn't changed...). Course being passed something like a string... (seems the most likely place you'd find it), in which case using .dup on the input string right back into the variable would be completely understandable. ie: string someStringTransformationWithCOW(string x) { //if COW'd then x = x.dup; //... return x; } Course having the input as char[] rather than string makes more sense for on the fly changes before returning it...
Re: I'm back
On Tuesday, 13 November 2012 at 10:53:49 UTC, Job wrote: Oh yes, likely see about revising the forum to allow either attaching/moving a post to an appropriate location, or allow a flagging system where we can remove spam posts like from Job... To do that, likely needs multiple votes, so say 10-20 votes for it to be removed/quarantined and for an admin group to confirm if it's spam or not (I'm sure Andrei and Walter can select a few appropriate people for that task/access). Same for flagging a user the admin would allow a spammer to appear/think he posted while in reality he was ignored being a known spammer.
Re: Growing a Language (applicable to @attribute design)
On Wednesday, 14 November 2012 at 22:23:17 UTC, Walter Bright wrote: On 11/14/2012 3:06 AM, Simen Kjaeraas wrote: But the syntax for built-in types is better, in that you don't need to write: auto x = int(1); If you're going to argue that D should have some facility to create user-defined literals that are arbitrary sequences of arbitrary characters, I think you're taking Guy's advice way beyond the breaking point. Hmmm... Correct me if I'm wrong, but you can create/use opAssign, correct? Although that doesn't work during initialization... struct MyInt { int i; ref MyInt opAssign(int rhs) { i = rhs; return this; } } MyInt x = MyInt(10); MyInt y; // = 15; //cannot implicity convert y = 15; writeln(x); writeln(y);
Re: @property needed or not needed?
On Monday, 19 November 2012 at 18:21:55 UTC, Mehrdad wrote: Why don't we just outright disallow expression-statements? After all, 2 + 3; should not be a valid statement, and so foo.property; should not be, either. Hmmm I would say if it's const/immutable and pure then it would be an error (Side effects considered after all), otherwise popFront may not work (it is a property I believe...right?). So let's assume I make some struct to call the PC Speaker (for whatever reason) then the following would break. struct PCSpeaker { int dingsCalled; void ding() @property { dingsCalled++; //some low level calls } } However if it was... void ding() @property const pure We know there's no side effects (and it can't modify the struct), which then 'ding' could be an error on it's own (Although without a return value that would make the signature completely useless).
Re: half datatype?
On Tuesday, 20 November 2012 at 09:11:07 UTC, Manu wrote: Nice case study! Thanks! Looks like a cool little game too :P Watched the video. Interesting looking game, but how long it was taking to move around the ships gives a sense of size, making me ask myself 'my god, how big IS that ship?'.
Re: Talk proposal (kinda): D Programming in D (Or: Writing idiomatic D code)
On Wednesday, 21 November 2012 at 22:47:02 UTC, Joshua Niehus wrote: On Wednesday, 21 November 2012 at 18:42:55 UTC, Leandro Motta Barros wrote: Well, this is actually a "talk proposal for someone else". I'd be the audience, not the speaker. TITLE: D Programming in D (Or: Writing idiomatic D code) +1 I'd like to add, maybe put some focus on "Range" oriented coding seeing as Phobos is full or ranges etc... And how it simplifies code because of it. Several times I've written a small range struct which handle managing blocks of memory (and lots of low level arithmetic); This removes the need for multiple extra variables handling location and low level counting when all you want to worry about is each item. Perhaps a talk on templates as well, when to use them, where to use them. Actually something I'd like some time is a video concentrating on a particular part of the library where they explain why they set it up the way they did (arguments, examples) as well as how to use some of the more complex use cases. I can do one involving my primes range (as an example). Hmmm a section also on when to use various key words (pure, @safe, nothrow, inout); Multiple times I've tried to add tags to better represent my functions only to have it break all over the place (because a nothrow calls something that's not a nothrow (but should/could be), 'to' is not pure, etc). Concentrating on the ranges more, once the transient front part gets settled (and if it's allowed) a part on when to use it (and how to declare it). Perhaps a part on how to properly use D without involving the GC. Hmmm so many more things I could throw in...
Re: Array Operations: a[] + b[] etc.
On Wednesday, 21 November 2012 at 18:15:51 UTC, Walter Bright wrote: On 11/21/2012 10:02 AM, John Colvin wrote: My vision of how things could work: c = a[] opBinary b[]; should be legal. It should create a new array that is then reference assigned to c. This is not done because it puts excessive pressure on the garbage collector. Array ops do not allocate memory by design. But if they wanted it anyways, could implement it as a struct... Here's a rough build... Should be fairly obvious what's happening. struct AllocatingVectorArray(T) { T[] data; alias data this; alias AllocatingVectorArray AVA; //forces slice operations for vector format only static struct AVASlice { T[] data; alias data this; this(T[] rhs) { data = rhs; } AVA opBinary(string op)(const AVASlice rhs) { assert(rhs.length == data.length, "Lengths don't match, cannot use vector operations"); AVA var; var.data = data.dup; mixin("var[] " ~ op ~ "= rhs[];"); return var; } } this(T[] rhs) { data = rhs; } ref AVA opAssign(T[] rhs) { data = rhs; return this; } AVASlice opSlice() { return AVASlice(this); } } unittest { alias AllocatingVectorArray!int AVAint; AVAint a = [1,2,3,4]; AVAint b = [5,6,7,8]; AVAint c; // c = a + b; //not allowed, 'not implemented error' // assert(c == [6,8,10,12]); c = a[] + b[]; //known vector syntax assert(c == [6,8,10,12]); c[] = a[] + b[]; //more obvious what's happening assert(c == [6,8,10,12]); }
Re: opDispatch to template members
On Thursday, 6 December 2012 at 23:01:19 UTC, deadalnix wrote: On Thursday, 6 December 2012 at 21:49:21 UTC, Phil Lavoie wrote: I mean automatically dispatch to template members, not doing it in a case by case fashion (using template if clauses for example). Thanks This is a known issue of the current design of opDispatch. It seems like there should be a way to separate template function calls to opDispatch and keep opDispatch's own template half separate. Hmmm... Some type of separator. It would likely have to allow a beginning tuple, as well as call opDispatch that would recognize it as such. In theory... auto opDispatch(T..., string method, V...)(V args) Assuming it would be allowed, T represents the template portion of a call. Since the ... makes it illegal to be first (in normal cases) it may allow a special rule in order to understand it's a passable tuple for templates only, and allowed for only the first and last arguments. Or would T[] be better? Then calling such an opDispatch may be... { static assert (!T.length) { return mixin("._inner." ~ method)(args); } else { return mixin("._inner." ~ method)!(T)(args); } } The rewrite of such a function call would be.. auto zeOtherString = outer.fun4( zeString ); outer.fun5!"popo"(); //No compilo amigo would become (I think?) //depending on how they do it... auto zeOtherString = outer.opDispatch("fun4")(zeString); auto zeOtherString = outer.opDispatch([], "fun4")(zeString); auto zeOtherString = outer.opDispatch(void[0], "fun4")(zeString); outer.opDispatch(["popo"], "fun5")(); Having the passable tuple after the method may be confusing, but might equally work... auto opDispatch(string method, T t, V...)(V args) (or is it 'T[] t'?) Allowing a blank (for t) wouldn't probably be allowed, so two opDispatches might have to be made, but that might be minor. Depends on what makes sense and how walter/andrei decide to handle if (if at all). If it still requires a separating type, you could always use void... auto opDispatch(T[], void, string method, V...)(V args) outer.opDispatch(["popo"], void, "fun5")(); or?? auto opDispatch(string method, T[], void, V...)(V args) //void and non-void attempted? Or always insert void silently? outer.opDispatch("fun5", ["popo"])(); outer.opDispatch("fun5", ["popo"], void)();
Re: Array Slices and Interior Pointers
On Tuesday, 11 December 2012 at 18:11:32 UTC, Robert Jacques wrote: On Tue, 11 Dec 2012 11:25:44 -0600, Alex Rønne Petersen wrote: Interior pointers are OK in the stack and registers, so taking pointers to fields inside aggregates should be fine so long as they are not stored in the heap. So what about unions? The pointer & lengths won't work well together if you mix them. Consider. struct S { union { int[] i; byte[] b; } } S s; s.i.length = 4; assert(s.i.length == 4); assert(s.b.length == 16); //fails assert(s.b.length == 4); //the implementation s.b = cast(byte[]) s.i; assert(s.b.length == 16); //true assert(s.i.length == 4); //fails assert(s.i.length == 16); //the implementation (last twelve Sigfaults probably) The only way to properly use that is to have one of the data types you always convert from/to, but the GC wouldn't know and might try them all; Although only the base pointer might be considered so...
Re: Is there any reason why arithmetic operation on shorts and bytes return int?
On Tuesday, 11 December 2012 at 12:53:38 UTC, monarch_dodra wrote: integer operations are always promoted to at least int. That's standard fare since C. I think it is a performance thing: Unpack into ints, oeprate, repack into ints. If memory serves me right, promotion to int is based more on CPU efficiency and code size than anything else (and yes packing and unpacking takes some 6 extra steps). Also with libraries possibly written by different compilers may have different results if they don't all agree on a common (default) type to return. Also most x86 operations for ints can be written as 1 byte opcodes, although for modern CPUs that kind of code generation may not be as efficient as it used to be. http://www.codeproject.com/Articles/6154/Writing-Efficient-C-and-C-Code-Optimization
Re: std.bitmanip improvements
On Thursday, 27 December 2012 at 10:16:51 UTC, Dmitry Olshansky wrote: IRC Era Scarecrow did an amazing job on it that covered a lot of enhancements including small string optimization, appending, slicing etc. I recall reviewing his code and it was a Phobos pull once but then it pulled out (for further enhancement? dunno). So definitely suggest you two to get in touch. I'm glad for the praise... :) Perhaps it seems silly, however I pulled it not because I needed to enhance it, but because it had trouble merging with other pulls. I looked at the error(s) and it was something like '13 white spaces mismatches'... How do you fix 13 white spaces? They're white space because you can't see them :P Had it been lines of code you can intelligently re-order or adjust them, but white spaces?? Sheesh... Maybe being lazy but it was a headache trying to figure out the diff patch and how to fix it, so haven't tried too hard on it yet. If someone happens across that I'll give it another go and see if there's any other fixes/enhancements I can throw on it; Maybe get it in before the next release.
Re: std.bitmanip improvements
On Friday, 28 December 2012 at 01:21:01 UTC, Marco Nembrini wrote: So the code was complete and working and the only problem was doing the pull on github? If so would you mind me trying to do that in your place? It seems worth spending some time on to get all those improvements in. In a nutshell, yes.. Is the latest version this one: https://github.com/rtcvb32/phobos ? I'll have to look at my sources, I may have been working on something else. I can't recall but I think the settings were 'sometimes reference', although that's not hard to fix, just need to to decide the best way to handle the data that way. I'll look over all my stuff tomorrow. Feel free to try and get it to merge/pull in GitHub.
Re: Ranges longer than size_t.max
On Saturday, 29 December 2012 at 01:18:37 UTC, Peter Alexander wrote: 1. Allow ranges to return BigInt for length. 2. Allow ranges like this but assert when .length overflows. 3. Allow ranges like this and just allow .length to overflow dangerously. 4. Do not allow ranges like this. Option 5: Incorporate (emulation code?) for cent/ucent, then consider that the same as 1 but returning cent rather than BitInt.
Re: Ranges longer than size_t.max
On Sunday, 30 December 2012 at 19:11:51 UTC, Dmitry Olshansky wrote: False. It's solely a question of FS used. NTFS supports files larger then 4 Gb regardless of version Windows (Win2K+ or even earlier). It doesn't matter what the bitness of OS in question is. I suspect 32bit linux also has > 4Gb files even with ext2 no problem. And e.g. FAT32 remarkably can't handle 4 Gb+ files with any OS. I was writing some code to go through the FAT12/16/32, and some interesting information was found (Although there was so much overhead I kinda stopped in the middle of it). FAT32 actually uses something like 28/29 bits for the sector id, the other 3-4 bits were flags like bad sectors, last sector and other minor data. At least that's what I remember off hand. http://en.wikipedia.org/wiki/Fat32
Re: Ranges longer than size_t.max
On Monday, 31 December 2012 at 17:47:36 UTC, Peter Alexander wrote: On Monday, 31 December 2012 at 17:43:34 UTC, Era Scarecrow wrote: On Saturday, 29 December 2012 at 01:18:37 UTC, Peter Alexander wrote: 1. Allow ranges to return BigInt for length. 2. Allow ranges like this but assert when .length overflows. 3. Allow ranges like this and just allow .length to overflow dangerously. 4. Do not allow ranges like this. Option 5: Incorporate (emulation code?) for cent/ucent, then consider that the same as 1 but returning cent rather than BitInt. Two problems with this: 1. Still complicates range code (have to accomodate for both size_t and ucent return value for .length). 2. ucent probably isn't enough either for these sorts of ranges. Perhaps, but having cent/ucent available would make a few people happy at least, although except for a few cases with databases and encryption it may not be that important right now. I remember trying to learn C/C++ and trying to do a very very simple code to get the number 1 doubled something like 100 times. After 31 it went to garbage (hey I was 14 at the time, god that was a long time ago). It took me a while to understand the problem. I ended up re-writing the whole thing in assembly that took 101 bytes (COM file) and could double the number as many times as I wanted.
Re: Ranges longer than size_t.max
On Monday, 31 December 2012 at 18:18:08 UTC, monarch_dodra wrote: On Monday, 31 December 2012 at 17:56:37 UTC, Era Scarecrow wrote: Perhaps, but having cent/ucent available would make a few people happy at least Not to change the subject, but couldn't we just implement Cent and UCent as library types, such as Complex, or HalfFloat? I'd be tempted to open an ER and see if walter is up for it... Yes we could. Just that they are already defined built-in types according to the specs. *shrugs* But changing your code from Cent to cent after it's properly implemented seems like a minimal change. If walter says go ahead (and I'm sure he won't have a problem with it), then I guess it's up to whoever to make it.
Re: Ranges longer than size_t.max
On Monday, 31 December 2012 at 18:55:04 UTC, Stewart Gordon wrote: Sector? Do you mean cluster? Probably. They mean the same thing to me. I would have thought it used the whole 32 bits for cluster number, with magic values for "unused", "end of chain" and "bad". In each case you don't need to point to the next cluster as well. Unless it supports something like marking an in-use cluster as bad but leaving until another day the task of moving the data from it into a good cluster. Wouldn't have been practical. Historically the FAT table was a layout of all the clusters that pointed to the next cluster, and used the largest number to denote EOF. (there were 8 codes or so reserved, I don't remember exactly). Taking the math if you were to lay it all out via FAT32 using the same scheme, you'd end up with 2^34 bytes for a single table. FAT by default had 2 tables (a backup) meaning 2^35 would be needed, that is just overhead (assuming you needed it all). Back then you had 8Gig drives at the most and space being sparse, 28bits makes more sense (1-2Gigs vs 16gigs-32gigs). Of course obviously it wouldn't make the table(s) bigger if the drive didn't support above X clusters. But looking through http://en.wikipedia.org/wiki/Fat32 there are indeed a handful of magic values for things like this. Anyway, that states that it uses 28 bits for the cluster number, but nothing about what the other 4 bits are for. But a possibility I can see is that these 4 bits were reserved for bit flags that may be added in the future. I don't remember where I read it, but I was certain they were used for overhead/flags; Course I was also reading up on Long File Name (LFN) too and directory structures. Likely lost somewhere in those texts. FAT32 would/could have supported files over 4Gig, however the Folder/FS Max filesize was 32bit, and anything over would have likely been more complex to incorporate, along with programs depending on them all being 32bit. Guess it was easier to make the hard limit rather than make it extend to further sizes. Plus programmers are going to be lazy and prefer int whenever possible. Hmmm actually back then long long's weren't supported (except maybe by gcc), so I don't think that was much an option.
Re: Cent/UCent as library types
On Monday, 31 December 2012 at 19:10:09 UTC, Jonathan M Davis wrote: but I don't see what the point is of library types for them, not when we already have BigInt. Fixed sizes means no GC/allocation for passing the data around to functions; And optimized assembly code. Beyond that, it doesn't seem highly important. But if it's around as a viable option people will begin using it. You never know when/where you could need it.
Re: std.bitmanip improvements
On Friday, 28 December 2012 at 01:21:01 UTC, Marco Nembrini wrote: If so would you mind me trying to do that in your place? It seems worth spending some time on to get all those improvements in. Well since this is going I've resumed some work on it, nice to see the opBinary works along with the opDollar. I seem to have problems figuring out where to tell my github source to get the current beta so I can just work/update from that. All of it is quite confusing to me.
Re: Required constness of opEquals (and opCmp) ?
On Wednesday, 2 January 2013 at 09:07:31 UTC, monarch_dodra wrote: My opinion is that supporting non-const opEquals makes no real sense, and adds a lot of useless complexity (and inconsistency) to the code. At best, it means silently accepting erroneous code... Until it explodes in someone else's face... If the code doesn't change anything, it should be const. I know in a sorting algorithmn I am testing with I created a struct that held three numbers. The comparing number, and ordering number (to check against stable sorting) and a counter for how many times that number was compared against. So there could be uses for non-const versions, but those shouldn't affect the rest of the library for a few use cases.
Re: version()
> The fact that everyone has their own work-around, and everyone has a > DIFFERENT work around is hard evidence that version() is > insufficient, and the current design is making D code WORSE. > Even Walter describes and supports the work-arounds to use > in his poses from years ago. Seems I'm joining in the middle of a debate, sorry if I say anything already answered in a previous post. I may be in error, if so likely ignore this. This seems to be more a talk about inconsistent use of version (and redundancies). I'll add my two cents. It seems to me that OS and architecture specific modifications (that would make use of version()) should be in it's own file, perhaps something like 'arch_specific.d' and 'os_specific.d'. That way any unique and domain/system specific inconsistencies/issues can be handled in one place. Like Windows, Posix, x86_64 code, etc. Making multiple source files to deal with specific OS's or other related issues seems like the whole issue with code duplication (Change one, gotta change it everywhere else too). So having a 'os_windows.d' and 'os_posix.d' and a 'os_freebsd.d' and whatever other possible combinations just seems to in the long run breed problems rather than solving them, especially if they are minor differences between them. The only time you should include version specific in your sources, is when the differences are only in one spot (anywhere in the code), only one source file, or compile time sources and pre-compiled modules cannot work together. That goes down to compiler implementation. Likely you'll be compiling from sources so that ceases to be the issue. Version, mixins, static if's and aliases effectively remove the need for a preprocessor, doing the same job in a more controlled way that wasn't ugly and doesn't require extra passes through the source. But excessively using any and all of these (or misusing) can make code appear as bad as anything in a C's .h file. D is not a religion; But everyone (well almost) understands the need for consistency, code cleanliness and separation of Architecture & OS specific code. So barring the most trivial uses of version (or only found in one spot ever) guidelines and recommendations should be put down. 'The D Programming Language' book Andrei published has maybe a whole Page on version() total. The exact guidelines to follow may not matter so much, so long as it's clean, simple to follow and remember, and makes enough sense that everyone tries to adopt it. I'm sure if Walter or Andrei put an article, coding standards, or said 'Just do it this way', everyone would likely follow suit; Mostly since it gives you a direction and not leaving you to make up something on your own or worse follow previous conventions that used a pre-processor in C or C++. Hope I haven't rambled too much.
Re: [OT] destroy all software (was Programming language WATs)
> So college wasn't all that bad to me. They still need to change the > funding model here in the states though. That shit is broken as fuck. > For some people, namely those that are talented and have good > self-motivation, it may very well be worth their while to skip that > mess. Probably doesn't work for physics though; it can be hard to do > experimental physics on your own ;) > > Also, the D newsgroup is probably better at teaching > programming than college. Hm. ;) I have refused to go to college if I can't pay for it upfront and easily, which was impossible. Right now I have an option to go leaving me without a debt. There's courses I want to take to get me further into programming, yet the options are either difficult to impossible based on location, or what I really want isn't a specific offered course, without a lot of extra bloat to it likely. Now I'm wondering what I should take. Should I even bother getting a CS degree? Or does someone think another option would be better?
Re: Apparently unsigned types really are necessary
> Would it be sane to add integer overflow/carry runtime checks in > -debug builds? This could probably solve such issues, but we'd need > some means to avoid this checks when necessary. I have asked before regarding getting some standard way to hold these values after an arithmetic operation. Comes down to problems making it portable (basically). Being as these are taken directly out of C's view of how to handle arithmetic (Which ignores the hardware's obvious view) we need to look at it twice. First, normal computations where we ask for a squared value, or something for a project we are working on that needs a good value. These are situations where overflow, carry, and where such effects would screw with our results. These should have checks. The second is algorithms, PRNGs, encryption, checksums, which rely on the behavior as it is. We would need a way to specify which ints needed to be checked; Or if you want to go the other direction, specify which ones specifically don't. I think having the checks in the debug mode would be wonderful, for when you need it. It almost seems more likely a new struct type would be made that does those checks for you and is replaced during release with it's emulated type (Not too unlike SafeInt Microsoft was making).
Re: Apparently unsigned types really are necessary
> My I propose the following modifications to the D lexer: > > ''' > White space may consist of: > - A comment between any two tokens. > - A single space between tokens that, if adjoined would be a > single token. > > All other white space (including \n \r \t \v, etc.) is > forbidden and a lexical error. > ''' > > With these additions, all valid D code will be so hard to read that > nobody will ever attempt to read it without first running a re-formatter > over it and once that is standard practice, everyone will see it in > there own preferred style. '\n' would be a invalid white space? Wow I see problems with that. Take a following debugging function of mine. Uses combination spaces, newlines and tabs. I think it's easy to read and understand. //(incomplete without the full class/struct, but you get the idea) void print() { writeln("\nP.empty = ", empty, "\nP.front = ", front, "\nP.position = ", position, "\nP.cap = ", cap, "\nP.map = ", map, "\n"); } That would instead becomes void print() { writeln("\nP.empty = ", empty, "\nP.front = ", front, "\nP.position = ", position, "\nP.cap = ", cap, "\nP.map = ", map, "\n"); } Far more likely the rules would have to be set for the editor to convert tabs into specific number of spaces and save it as such (and convert them back if they want). Otherwise in said projects, enforce certain rules for the project regarding formatting and reject it otherwise until they fix it.
Re: Apparently unsigned types really are necessary
> Points: > 1) that 2nd formatting still includes whitespace that would > be illegal > (e.g. every place but between 'void' and 'print' and in the > strings > litereals). > 2) The *point* is to turn code into an unreadable mash on a > single line. > 3) The entire proposal is satire. Ahh, i had the impression from the list that all whitespace tokens were referring to a single statement line, not as a whole. Guess the only way to make it so spaces (1 or more) were whitespace, would be if we still use a fixed 80character width screen for our editors, then leftover whitespace becomes formatting. But it seems sufficiently stupid to do that, filesize being the largest part. I know all of C appeared in it's formatting, to allow you to drop all whitespace (with minor exceptions) into a single line, which is why /**/ comments were used and c++'s // ones were added later. Although fun to do a whole lot on a single line, i don't know if i would want to. /*C code following the follow proposal; tested and works. Not bad for 165 characters of pure code.*/ isprime(int n){int cnt=2;if(n<2)return 0;for(;cnt
Re: Apparently unsigned types really are necessary
> From: "Nick Sabalausky" > > ''' > > White space may consist of: > > - A comment between any two tokens. > > - A single space between tokens that, if adjoined would > be a single token. > > > > All other white space (including \n \r \t \v, etc.) is > forbidden and a > > lexical error. > > ''' > > > > With these additions, all valid D code will be so hard > to read that nobody > > will ever attempt to read it without first running a > re-formatter over it > > and once that is standard practice, everyone will see > it in there own > > preferred style. > > Hah! I like it :) It does have a certain amount of sense it makes... but if that were really an issue, then having your won formatter strip the unneeded spaces and then re-introducing them back seems trivial, in which case a indentation tool would be more likely to be used (GNU indent anyone?). It does however become an issue regarding debugging, if sources are compiled against said compacted sources in that way. Everything would be on line 1, and other such messes. Course if your compiling the sources yourself and run it through your formatter your fine. But if someone else has their own format and download the source and reformat it to their format, line 117 may not point to anything, or point to the wrong object, or worse yet, if an assert was thrown and it was an unrelated passing assert; that is with the assumption you use a program compiled with debugging flags and you don't rebuild said executable. And most importantly of all. I quote "If it ain't broke, don't fix it".