Re: struct initializer
On Wednesday, 29 November 2023 at 16:48:09 UTC, Paul Backus wrote: ... it even supports named arguments: - Witch version of DMD supports named arguments? Is it an experimental compiler option?
Re: interface inference
On Tuesday, 28 November 2023 at 15:46:18 UTC, Paul Backus wrote: On Thursday, 23 November 2023 at 19:17:20 UTC, Antonio wrote: Basically, the ternary conditional ```?:``` result type is not inferred even if the type returned by the two possibilities are the same. **Is it a bug or the expected behaviour?** Known bug, first reported in 2009: https://issues.dlang.org/show_bug.cgi?id=3543 Thanks Paul (again :-) ) Oh my!!! I wrote this question ```"On Thursday, 23 November 2023 at 19:17:20 UTC, Antonio wrote:"``` And the original bug was ```Reported: 2009-11-23 03:24 UTC by nfxjfg ``` ***The same date :-)... 14 years before***
Re: interface inference
On Tuesday, 28 November 2023 at 14:10:30 UTC, Dom DiSc wrote: On Tuesday, 28 November 2023 at 11:01:14 UTC, Antonio wrote: ```d I aOrB(bool check){ if(check) return new A(); else return new B(); } ``` **Is it the expected behaviour for ternary conditional?** Here the compiler knows what type to return (from the function signature). But the ternary operator doesn't know this, Why?... ternary operators should deduce returning type the same way need to be of the same type (or implicitly convert to a common type). It is a common type: the ```I``` interface. In fact, if you use ```abstract class``` instead ```interface```, it works: ```d abstract class I { bool check(); } class A : I { override bool check() =>true; } class B : I { override bool check() =>false;} I aOrB(bool check) => check ? new A() : new B(); void main() { assert( aOrB(true).check ); } ``` Why ternary operator accepts covariance rules applied to base class, but not applied to interface? About cast(I)... it allows "illegal" castings causing runtime segmentation faults if not used carefully: ```d class X { string xname() =>"I'm x"; } class Y { string yname() =>"I'm y"; } void main(){ (cast(Y) new X()).yname; // Runtime segmentation fault } ``` This is another good reason to avoid using cast when possible.
Re: interface inference
On Thursday, 23 November 2023 at 19:17:20 UTC, Antonio wrote: ```d interface I { bool check(); } class A : I { bool check() =>true; } class B : I { bool check() =>false; } I aOrB(bool check) => check ? new A() : new B(); void main() { assert( aOrB(true).check ); } ``` Compiler error: ```d x.d(11): Error: cannot implicitly convert expression `check ? new A : new B` of type `object.Object` to `x.I` ``` I'm forced to explicitly write the cast this way ```d I aOrB(bool check) => check ? cast(I) new A() : cast(I) new B(); ``` But it is not necessary when I write same code using if/else/return statements ```d I aOrB(bool check){ if(check) return new A(); else return new B(); } ``` **Is it the expected behaviour for ternary conditional?**
Re: interface opEquals
On Saturday, 25 November 2023 at 01:15:34 UTC, Alexandru Ermicioi wrote: On Friday, 24 November 2023 at 17:39:10 UTC, Antonio wrote: ... Dunno if this might help, but I noticed that `==` sometimes calls `opEquals(const Object) const` instead of overload defined on class/interface, you might try and override it as well, and delegate to your overload that deals directly with `IOpt`. Best regards, Alexandru. Thangs Alexandru, It works. ...but why?
Why this compiles?
In this example, ```a``` and ```b``` vars are not of the same type and don't implement the same interface. **why ```assert(a==b)``` compiles?** ```d interface IOpt(T) { bool opEquals(const IOpt!T) const @safe pure; } class None(T) : IOpt!T { bool opEquals(const IOpt!T other) const @safe pure => true; } void main() { auto a = new None!int(); auto b = new None!string(); assert(a==b); } ```
Re: interface opEquals
On Thursday, 23 November 2023 at 21:52:56 UTC, Jonathan M Davis wrote: I'd have to take the time to study your code in detail to see whether what exactly you're seeing makes sense or not ... My apologies... I should have proposed a more specific example. ```d interface IOpt { bool opEquals(IOpt other) const @safe pure; } class None : IOpt { bool opEquals(IOpt other) const @safe pure => true; } void main() { None a = new None(), b = new None(); IOpt a2 = a, b2 = b; assert(a == b); assert(a2 == a); assert(b2 == b); assert(a2 == b2); // fails!!! } ``` == on classes results in the free function, opEquals, in object.d being called. That function does a variety of checks such as checking whether either reference is null (to avoid dereferencing null) and using is to compare the address of the class references first (to avoid calling the class' opEquals if both references are to the same object). It also makes sure that both rhs.opEquals(lhs) and lhs.opEquals(rhs) are true for == to be true to avoid subtle bugs that can come into play when comparing a base class against a derived class. https://github.com/dlang/dmd/blob/master/druntime/src/object.d#L269 Replacing ```interface``` by ```abstract class``` removes the problem. But I have not enough D knowledge to discover why interface version is not working Thanks Antonio
Re: Doubt about type Inference on templates
On Wednesday, 22 November 2023 at 19:37:58 UTC, Paul Backus wrote: This is a bug/limitation in the compiler. I couldn't find an existing report on issues.dlang.org, so I've reported it myself as [issue 24255][1]. Wow: It is a very concise bug example. I tested with ```ldc``` ant it fails too. For now, I think the best way to work around it is to specify the type in the lambda, as in `(int i) => i%2 == 0`. agreed The reason you see `void` is that when the compiler cannot figure out the type of a function literal, it treats it as a template function: ```d static assert(__traits(isTemplate, i => i % 2 == 0)); ``` And for silly historical reasons, when the compiler tries to determine the type of a template, it returns `void` instead of giving an error: ```d template example() {} static assert(is(typeof(example) == void)); // what?? ``` Thanks Paul!!!
interface opEquals
```d interface IOpt(T) { T value(); bool empty(); bool opEquals(IOpt!T other); } class None(T) : IOpt!T { bool empty() => true; T value(){ throw new Exception("None has not a value"); } bool opEquals(IOpt!T other)=>other.empty; } class Some(T) : IOpt!T { this(T value) { this._value = value; } bool empty() => false; T value()=> _value; bool opEquals(IOpt!T other)=>!other.empty && other.value==_value; private T _value; } IOpt!T some(T)(T v)=>new Some!T(v); IOpt!T none(T)()=>new None!T; void main() { assert(new Some!int(1) == new Some!int(1)); assert(new None!int == new None!int); assert(none!int.opEquals(none!int)); assert(none!int == none!int); } ``` It compiles, but last assertion ```assert(none!int == none!int);``` fails ``` core.exception.AssertError@testiface.d(33): Assertion failure ``` To avoid "extrange effects" I test an alternative equality that fails too: ```d assert( (cast (IOpt!int) new None!int) == (cast (IOpt!int) new None!int)); ``` What seems strange to me is that ```none!int.opEquals(none!int)``` works properly. **Questions** * Why, when applied to interface, ```opEquals``` called directly behavior is not the same that when calling ```==``` ? * Is it the expected behaviour?
interface inference
```d interface I { bool check(); } class A : I { bool check() =>true; } class B : I { bool check() =>false; } I aOrB(bool check) => check ? new A() : new B(); void main() { assert( aOrB(true).check ); } ``` Compiler error: ```d x.d(11): Error: cannot implicitly convert expression `check ? new A : new B` of type `object.Object` to `x.I` ``` Basically, the ternary conditional ```?:``` result type is not inferred even if the type returned by the two possibilities are the same. **Is it a bug or the expected behaviour?**
Doubt about type Inference on templates
Just for fun, I'm trying to implement an alternative base library to avoid template/mixin/static/traits code with only one objective: make "intelliSense" code analyzers tasks easier. I need "Generics"... but D has not generics: I use templates in the "simplest" possible way I.E.: ```d interface IIterable(T) { bool empty(); void popFront(); T front(); } IIterable!S toIterable(S)(S[] source) => new ArrayIterable!S(source); IIterable!S filter(S)(IIterable!S source, bool delegate(S item) predicate) => new Filter!S(source, predicate); IIterable!S filter(S)(S[] source, bool delegate(S item) predicate) => toIterable(source).filter(predicate); // ... ``` Then, in main.d I do ```d import std.stdio; void main(){ [1,2,3,4,5,6].toIterable!int.filter!int(i=>i%2==0).map!int(i=>i*2).toArray.writeln(); } ``` It works properly... until I remove the ```!int``` from the ```filter``` method. ``` main.d(3,38): Error: none of the overloads of template `filter` are callable using argument types `!()(IIterable!int, void)` iterable.d(21,13):Candidates are: `filter(S)(IIterable!S source, bool delegate(S item) predicate)` iterable.d(23,13):`filter(S)(S[] source, bool delegate(S item) predicate)` ``` Basically, it doesn't know witch version of ```filter``` to use, because it is inferring `i=>i%2==0` is `void` ?!?!?! ``` !()(IIterable!int, void) ``` If I explicitly write `(int i)=>i%2==0`, it compiles correctly again. **Is it mandatory to explicitly tell that `S` is `int` when ```IIterable!S source``` is `IIterable!int` alredy?**
Re: What is :-) ?
On Monday, 20 November 2023 at 16:47:13 UTC, Paul Backus wrote: You can put the `delegate` keyword in front of the function literal: ```d auto createCounter = delegate (int nextValue) => () => nextValue++; ``` This syntax is documented in the spec's section on [Function Literals][2] (look at the grammar box and the examples). [2]: https://dlang.org/spec/expression.html#function_literals Thaks Paul
Re: What is :-) ?
On Monday, 20 November 2023 at 16:32:22 UTC, evilrat wrote: ```d // this is a function returning a delegate auto createCounter(int nextValue) => auto delegate() => nextValue++; Thank you!!!. Compiler forces me to omit "auto" keyword ```d auto createCounter(int nextValue) => delegate () => nextValue++ ; ``` Explicit return must be specified after "delegate" keyword ```d auto createCounter(int nextValue) => delegate int () => nextValue++ ; ``` When declaring a type (variable or parameter) is when keywords order must be "inverted" ```d import std.stdio; int callWith10( int delegate (int) x) =>x(10); void main(){ int j=100; // Explicit writeln( callWith10( delegate int (int i)=>i+j ) ); // Inferred writeln( callWith10( i=>i+j ) ); // OMG writeln( ( i=>i+j ).callWith10 ); } ``` // this is a function returning a function auto createCounter(int nextValue) => auto function() => nextValue++; ``` I think this will not work, because nextValue is defined out of the returned function scope: you must return a closure (delegate). Thanks a lot evilrat!!! **From your answer (and other ones too) I have to say that...** * **D Closures rocks!!!** It is hard to find something so powerful in other natively compiled languages: **Heap + GC** has it's advantages. * **D offers nice syntax features**: you can declare arrow methods very similar to dart, or assign an arrow function/delegate to a variable like Javascript/Typescript lambdas.
Re: What is :-) ?
On Monday, 20 November 2023 at 13:25:48 UTC, Paul Backus wrote: On Monday, 20 November 2023 at 08:47:34 UTC, Antonio wrote: - What is the way to do ```writeln``` work with ```Counter``` function the same way it works with ```next``` function? `writeln()` should do it. It does not do the same: It shows an address, not the function signature. Because I need to understand "why", I propose a second example (with some additional info based on @evilrat proposals :-) ): ```d import std.stdio; void main() { auto createCounter = (int nextValue) => (int dummy) => nextValue++; auto getNext = createCounter(10); writeln( "'getNext' is ", getNext ); writeln( "'createCounter' is ", createCounter ); writeln( "'typeof(getNext).stringof' is ", typeof(getNext).stringof ); writeln( "'typeof(createCounter).string' is ", typeof(createCounter).stringof ); } ``` The output is ``` 'next' is int delegate(int) pure nothrow @nogc @safe 'createCounter' is 557FFCC00968 'typeof(getNext).stringof' is int delegate(int dummy) pure nothrow @nogc @safe 'typeof(createCounter).string' is int delegate(int dummy) pure nothrow @nogc @safe function(int nextValue) pure nothrow @safe ``` **Why ```writeln``` doesn't treat the same way ```getNext``` and ```createCounter```?** Because ```getNext``` is a delegate and ```createCounter``` is a function. **Why this is a function and not a delegate?** ```auto createCounter = (int nextValue) => (int dummy) => nextValue++;``` Syntactically I dont see any difference: ```auto name = "expression returning a delegate"``` The reason is **D compiler takes the decision**. If you make ```createCounter``` to depend on an external variable, it will be treated as delegate (because it has context information associated to the function: a closure) ```d import std.stdio; void main() { int diff = 1; auto createCounter = (int nextValue) => () { scope(exit) nextValue+=diff; return nextValue;}; writeln( "'typeof(createCounter).string' is ", typeof(createCounter).stringof ); } ``` Will output that createCounter is a delegate: ``` 'typeof(createCounter).string' is int delegate() pure nothrow @nogc @safe delegate(int nextValue) pure nothrow @safe ``` What "breaks" my mind is that a compiler decision (treat a piece of code as function or delegate) is not completely transparent causing "side" effects on your code (writeln doesn't work the same way: it shows the delegate signature, but not the function signature). But the decision of the compiler is predictable and you can argue different effects are not side effects: only something you should pay attention to. **This long and winding road toke me to a third and crazzy question** Is there any way to force D compiler to treat this "createCounter" declaration as **delegate** instead of **function**? ```d auto createCounter = (int nextValue) => () => nextValue++; ```
Re: What is :-) ?
On Monday, 20 November 2023 at 09:11:07 UTC, evilrat wrote: if you meant to take the function/delegate and not invoke try `` instead, otherwise it expects the parameters. If you execute ``` writeln( "'Counter' is ", ); ``` It shows the Counter address: ``` 'Counter' is 557F2567F940 ``` Not the function signature like it does with ```next``` I propose a simple change: ```d void main(){ auto Counter = (int nextValue) => () => nextValue++; auto next = Counter(10); writeln( "'next' is ", next ); writeln( "'Counter' is ", Counter ); } ``` first ```writeln``` shows the signature of next: ``` 'next' is int delegate() pure nothrow @nogc @safe ``` second writeln shows the address of Counter ``` 'Counter' is 55568953C910 ``` - Why writeln doesn't treat ```next``` and ```Counter``` the same way? (I think I understand why, but it shows a "low" level difference of something that syntactically is equivalent) - What is the way to show Counter signature using ```writeln``` (if possible)? ```
What is :-) ?
If I run this code ```d import std.stdio; void main(){ auto next = Counter(10); next().writeln; next().writeln; next().writeln; // What is "next" function? writeln( "'next' is ", next ); // What is "Counter" function? This fails // writeln( "'Counter' is ", Counter ); } auto Counter(int nextValue) => () => nextValue++; ``` Executing this code results in: ``` 10 11 12 'next' is int delegate() pure nothrow @nogc @safe ``` Now, I uncomment the ```writeln( "'Counter' is ", Counter );``` line and compiler says ``` /home/antonio/Devel/topbrokers/whatsapp-srv/admin/x.d(12): Error: function `x.Counter(int nextValue)` is not callable using argument types `()` /home/antonio/Devel/topbrokers/whatsapp-srv/admin/x.d(12): too few arguments, expected 1, got 0 ``` I understand the problem with UFCS (``next`` is not using UFCS because it is a delegate defined in the own main() function, and ``Counter``` without () is treated as a function call because it is UFCS eligible ) - What is the way to do ```writeln``` work with ```Counter``` function the same way it works with ```next``` function?
Re: how to assign multiple variables at once by unpacking array?
On Sunday, 8 October 2023 at 06:02:14 UTC, Jonathan M Davis wrote: The problem is that the compiler needs to be able to verify that the types match, and when the return type of a function is a dynamic array such as int[], it has no way of knowing how many elements the array has and therefore can't verify at compile time that the assignment will work. add a runtime check to verify that the number of elements match, but that's not the sort of thing that you typically do with a statically typed language. I agree. And solutions like "algebraic types" used by typescript are not applicable to D (You cant declare int|undefined) ```typescript const sorted=([first,...xs]:T[]):T[] => first===undefined ? [] : [ ...sorted(xs.filter(x=> x<=first )), first, ...sorted( xs.filter(x=> x > first)) ]; console.log( sorted([1,2,3,4,-1,-2,-3]) ); ``` But it should with pattern matching ```D auto sorted(T)(T[] entries) => match(entries) { case [item, ...others] => ... otherwise => [] } ``` Or with overloading (patter matching expressions on function signature... similar to haskell) ```D auto sorted(T)(T[] [item, ...others]) => ...; auto sorted(T)(T[] []) => []; ``` Well, not really: because compiler can't predict witch "sorted" version will be called on compile time. (May be it should be a syntax suggar of an unique sorted method with match in the body) However, while there are some benefits to being able to do this, the response by many programmers from statically typed languages is that it's cleaner to create a struct for this sort of thing I completly agree , since then the values are contained together, and they have names associated with them (since they'll be member variables of the struct). So, while some programmers definitely want tuple types to be built into D, a number of others don't like the idea. As such, it's an open question whether we'll ever have such tuples in D. Destructuring is only a **Syntax sugar** applicable to well known types (i.e. Structs). It is not related (exclusively) with tuples: The type of a function call (or a parameter) is perfectly known. Typescript applies destructuring based on type matching (type members names): ```typescript type ICounter = { inc: ()=>void dec: ()=>void value: ()=>number } function Counter(n:number=0):ICounter { return { inc: ()=>{ n++ }; dec: ()=>{ n-- } value: ()=> n; } } const {inc,value} = Counter(); inc(); inc(); console.assert( value() === 2 ); inc(); console.assert( value() === 3 ); ``` It could be portable with Structs in D. Personally, I found it is specially useful with parameters for "dependencies injection": ```typescript function CarsDAO( {db:{ withTransaction }, logger:{ info }}: IContext ):ICarsDao { return { createCar, updateCar } function createCar(data:CarDto):Promise { info("Lets create a car"); return withTransaction( trx=> trx.executeQuery("insert . returning key") ); } } const context:IContext = { logger: Singleton(logger), db: Singleton(Db), carsDao: Singleton(CarsDao), } (async ({ carsDAO:{ createCar }, logger }:IContext)=>{ data:CarDTO = { registration: "ASD1232", model: "Citroën XS" }; const key = await createCar( data ) logger.info( `Car ${key} has been registered`); })(context); ``` This kind of destructuring is semantically rich. Note: The "hard" part for this kind of solutions (dependency injection not based on classes) is the clousures management, and D solves it magnificently... Either way, the unpacking of dynamic arrays likely stands no chance whatsoever of ever being added, > because it would require runtime checks to determine whether the unpacking was valid. This is what pattern matching, some day, at runtime, should solve :-) -- Antonio
Re: My programs issues
On Wednesday, 10 August 2022 at 13:13:20 UTC, Adam D Ruppe wrote: On Wednesday, 10 August 2022 at 12:36:42 UTC, pascal111 wrote: 1) I used "exit()" from "core.stdc.stdlib;" module, but someone can say this isn't the D way to exit the program. It is better to simply return a value from main instead. 2) I used "goto", I heard from someone before that using "goto" isn't good programming feature. Don't listen to people who are wrong. "goto" is a bad "structured programming" feature, but not a bad programming feature.
Re: BASIC "sgn" function equivalent
On Thursday, 28 July 2022 at 15:03:34 UTC, H. S. Teoh wrote: Just use the source, Luke! Phobos is open source for a reason. https://github.com/dlang/phobos/blob/8280b1e7de6cca4dc9a593431591054a5b3aa288/std/math/traits.d#L694 T :-) ```d // @@@TODO@@@: make this faster ```
Re: BASIC "sgn" function equivalent
On Thursday, 28 July 2022 at 12:13:31 UTC, Antonio wrote: Use isFloating!T and isIntegral!T traits. The standard library **sng** function is a good example: https://dlang.org/library/std/math/traits/sgn.html ```d import std.traits : isFloatingPoint, isIntegral; int sgn(T)(T x) if (isFloatingPoint!T || isIntegral!T) { if(x<0) return -1; else if(x>0) return 1; else return 0; } void main() { import std.stdio; writeln(sgn(-1234)); sgn(-1213.32).writeln; 1234.sgn.writeln; } ```
Re: BASIC "sgn" function equivalent
On Thursday, 28 July 2022 at 12:02:54 UTC, pascal111 wrote: I'm making an equivalent of "sgn" function of BASIC language, and I used "(T)" in its definition, but the function can receive wrong data by passing string data to it, how we can solve it? Use isFloating!T and isIntegral!T traits. The standard library **sng** function is a good example: https://dlang.org/library/std/math/traits/sgn.html
Re: null == "" is true?
On Wednesday, 20 July 2022 at 13:35:14 UTC, Kagamin wrote: On Tuesday, 19 July 2022 at 18:05:34 UTC, Antonio wrote: In a relational database, `NULL` is not the same that `""`... and `NULL` is not the same that `0`. Are semantically different and there are database invariants (like foreign keys) based on it. Trying to "mix" this concepts in a database is a mistake. So, it's an implementation detail or a relational database that leaks into business logic because nobody thought about it? Just because a relational database has many features, it doesn't mean business logic must use them all, it must use only what makes sense for business logic. It is not about "so many fetaures"... it is about entity model and how relational database stores it. General purpose programming languages include their own representation to the NULL concept that is not "relational model" dependent: Optional, Maybe, Nullable, Union types What semantics your domain models implement? Is it semantics of all features of a relational database or is semantics of business logic? Database is an **strict repository**: it stores the entity model with relational semantics including strict invariant management (primary keys, foreign keys, field types, nullablility, ...) and following normalization rules (3th normal form, at least). It is, basically, a "consistent" model. Business logic **trust on database repository invariants** and implements whatever your Business Model require (i.e.: complex model operations involving multiple repository operations). Business works using Objects/Entities of the domain and it is required a way to map this to relational model (ORM or manual SQL)... Usually in a specific "Data" or "DAO" layer. Transactions are your friend (The only way to ensure that high level invariants are enforced) If you can't be confident with database invariants (because you are using NoSQL repository like MongoDB or DynamoDB or an Old ISAM MySQL or "trash" models over relational engine) then you need to "move" all these "consistency" control to the business layer developing workflows/processes that must be ready to work with "inconsistent" data... (You can read this article I wrote 2 years ago about SQL/NoSQL solutions and Brewer's conjecture: https://qr.ae/pvklQA) Business "architecture" based on a single repository is the simplest one... But the pleasure of trusting on a relational database is always welcome.
Re: null == "" is true?
On Tuesday, 19 July 2022 at 16:55:39 UTC, Kagamin wrote: As I understand, in your scenario there's no difference between null string and empty string, they both work like empty string, and D treats them as empty string. That's what I mean when I said that distinction between null and empty is meaningless. Sorry Kagamin... I dindn't read this comment and I added a very large answer to the next one that has no sense :-p. I miss being able to delete answers from the forum :-) **Yes... I decided to treat the same way internally** for strings. Previously * `DtoVal!(Null, string)( null)` was equivalent to `DtoVal!(Null,string)( Null() )` * `DtoVal!(Null, Person)( null)` was equivalent to `DtoVal!(Null,string)( Null() )` Currently * `DtoVal!(Null, string)( null )` is equivalent to `DtoVal!(Null,string)( "" )`; * For other types this will raise a runtime exception: `DtoVal!(Null, Person)( null )`. * The correct way of is `DtoVal!(Null, Person)( Null() )` Basically, **`null` is completely useless and out of my code** with the exception of strings. Best regards Antonio
Re: null == "" is true?
On Tuesday, 19 July 2022 at 17:05:27 UTC, Kagamin wrote: Also what's the difference between null and empty phone number? In a relational database, `NULL` is not the same that `""`... and `NULL` is not the same that `0`. Are semantically different and there are database invariants (like foreign keys) based on it. Trying to "mix" this concepts in a database is a mistake. When you treat with Domain Models, you try to represent this semantics in all levels of your software... including APIs If your address has not a reference to the city... then there is a `city_code` field with `NULL` value in your database and the Address model object has a city property representing this Null value with the tools that language/library offers to you: `Nullable!City` or `Sumtype!(Null, City)` or `Optional` or ...). `Null` is then a valid value state that has nothing related to *`null` pointers*... to avoid confusion, I talk about `Null` instead `null`. I, personally, prefer to use Union types (algebraic types) like `int | Null | ...` because it is the best option to introduce the Undefined state (that allows statically typed data to represent the absence of a property). `Sumtype!(Undefined,Null,int)` instead `Optional!(Nullable!int)` Then there is the `match!` syntax, the unified way to treat JSON serialization and the easy way to implement a custom "dot" accessor that propagates the Null or Undefined state in a chain of references: ```d person.ns.address.ns.city.ns.name.match!( (string name){ ... } (Null) {...} (Undefined) { ... } ) ```
Re: null == "" is true?
On Tuesday, 19 July 2022 at 08:10:25 UTC, Kagamin wrote: On Monday, 18 July 2022 at 21:23:32 UTC, Antonio wrote: I will study it in detail and report (if required). May be, I will write the DTO problem with D article if I find time in august. In my experience null and empty in DTOs usually play the same logical role. It's a very contrived technical difference without practical usage, such distinction is way beyond any business logic. Even if you implement this distinction, I'm not sure anybody will carefully pay attention to it. In languages that make difference between null and empty, null is often replaced with empty to work around problems with null, such codebase can't properly preserve null values. When you have to "patch" information partially (i.e.: update only the name and the phonenumber, but not the birthdate) or you must return in a REST partial information (because graphql or custom REST) there is only 2 ways to represent this "possible missing properties" * Maps (key->value) or similiar (i.e.:JSon objects): You can include or not keys in the map: If you don't want to update the birthdate, don't include the birthdate key in the DTO. * Structs (or any kind of structured data that can be validated at compile time): There is no possibility to say that some properties of the struct can be not present... Well, you can if you begin to manage Algebraic Types (Union types): `height: int | undefined` NULL is not the same that UNDEFINED The distintion is really important: NULL is a valid value (i.e.: The person phonenumber is NULL in database)... Of course, you can represent this concept natively in you language (Nullable, Optional, Maybe ...) but it is not the same that UNDEFINED... because UNDFINED says "This property has not been assigned to DTO... do not take it into account". The summary is that a DTO that works like a Map needs to represent the absent key ant this is not the same that the Null value Example: ```d struct Null { /*...*/ } struct Undefined { /*...*/ } struct ContactDto { DtoVal!(Undefined, string) name DtoVal!(Undefined, Null, string) phonenumber, DtoVal!(Undefined, AddressDto) address } // ... ContactDto data = {phonenumber:Null(), address:{city:{code:"BCN"}}}; updateContact(id, data); ```
Re: null == "" is true?
On Monday, 18 July 2022 at 17:20:04 UTC, Kagamin wrote: ... If you want such difference, use the Nullable wrapper or Algebraic. I do :-) In fact, I use algebraic types supporting Null and Undefined for DTOs representation (and REST APIs). But I discovered some "rare" side effects in libraries like vibe.d and structs where, sometimes, am empty string is deserialized as null (value is null) and I have to assume that null in an string is always "" for avoiding this weird effects I'm under pressure to meet deadlines and a team that is telling me "Why D instead typescript, Antonio?"... One month ago I reported some questions in forums or git repos... but I have to finish my work and 2 hours stoppers are not acceptable now. I will study it in detail and report (if required). May be, I will write the DTO problem with D article if I find time in august.
Re: null == "" is true?
On Tuesday, 12 July 2022 at 20:36:03 UTC, Antonio wrote: Honestly, it is difficult to understand for newcomers... there is a reason, but there is a reason in javascript for `0 == ''` too Correction ```d string a = null; assert(a is null); assert(a == ""); string b = ""; assert(b !is null); assert(b == null); ```
Re: null == "" is true?
On Tuesday, 12 July 2022 at 18:56:43 UTC, Paul Backus wrote: On Tuesday, 12 July 2022 at 16:40:38 UTC, H. S. Teoh wrote: Because an empty string is, by default, represented by an empty slice of the null pointer. Do not rely on this, however; it's possible sometimes to get an empty string that isn't null, e.g., if you incrementally shrink a slice over a string until it's empty. In that case, .ptr will not be null, but the string will still be empty. Always compare strings against "" rather than null, because the latter may not do what you think it does sometimes. This is actually 100% reliable when comparing with the `==` operator because two empty strings always compare equal with `==`, regardless of what they point to. string s = "hello"; string empty1 = s[0 .. 0]; string empty2 = s[1 .. 1]; assert(empty1 == null); assert(empty2 == null); assert(empty1 == empty2); The real problem is that `s == null` looks like it does one thing (test for a null pointer) while actually doing something slightly different (test for an empty string). Then: ```d string a = null; assert(a is null); assert(a == ""); string b = ""); assert(b !is null); assert(b == ""); ``` Honestly, it is difficult to understand for newcomers... there is a reason, but there is a reason in javascript for `0 == ''` too
null == "" is true?
It works ```d void main() { assert(null==""); } ``` why?
vibe.d Serialize/Deserialize SumType to/from json
D offers `SumType` struct to manage tagged Union types. But there is no support for managing it's Json serialization/deserialization (using vibe.d) Is it a way to add `fromRepresentation` and `toRepresentation` to `SumType` (or a way for creating a custom struct "inheriting" SumType with serialization capabilities)? Thank you for advanced.
Re: How to check if something can be null
On Friday, 1 July 2022 at 15:35:00 UTC, Adam D Ruppe wrote: On Friday, 1 July 2022 at 13:48:25 UTC, Antonio wrote: I has been using this pattern each time something needs special treatment when it can be null: i'd prolly check `static if(is(typeof(null) : T))` which means if the null literal implicitly converts to type T. Perfect!!! Thanks Adam. there's also the bludgeon __traits(compiles, v is null) too lol love it X-) !!! may be this is the Swiss knife I was waiting for...
Re: How to check if something can be null
On Friday, 1 July 2022 at 13:48:25 UTC, Antonio wrote: -Why? I realized Json is an struct (not an object)... and I supose, it is managing null asignation manually (as a way to build Json(null)). -Whats the correct whay to test if something can be null? That's my question :-p
How to check if something can be null
I has been using this pattern each time something needs special treatment when it can be null: ```d void doSomething(T)(T v) { import std.traits: isAssignable; static if( isAssignable!(T, typeof(null))) { if(v is null) writeln("This is null"); else writeln("This is not null"); } else { writeln("This can't be null"); } } ``` and then ```d void main(){ // output: This is null doSomething!string(null); // output: This is not null doSomething("Hello"); // output: This can't be null soSomething!int(1); } ``` Problem appears with `vibe-d` `Json`. ```d void main(){ doSomething!Json(null); } ``` Compiler outputs `Error: incompatible types for `(v) is (null)`: `Json` and `typeof(null)` -Why? -Whats the correct whay to test if something can be null?
Re: int | missing | absent
On Monday, 27 June 2022 at 23:05:46 UTC, Steven Schveighoffer wrote: On 6/27/22 9:03 AM, Antonio wrote: On Wednesday, 22 June 2022 at 01:09:22 UTC, Steven Schveighoffer wrote: On 6/2/22 9:24 AM, bauss wrote: I feel it's too loose to make a best effort, and leave the rest up to initial values, or just ignore possibly important information during parsing. May be for your case Steve. I need to represent in a "typed" way complex structures where some properties can be "undefined" (not present in json) and where null value is a valid value (and not the same that "undefined" ones)... basically, the algebraic type Undefined | Null | T I see what you are saying. What needs to happen is first, you need a type wrapper that does this, which defaults to undefined. Then mark it optional so it's OK if it doesn't appear. Then only if the field is not present will it be marked as undefined. It may even be useful to make the type wrapper itself always optional, rather than having to mark it optional. Exactly. This issue/example in vibe-d treats about this solution and the annoying change of behavior treating "null" when @optional attribute is present: https://github.com/vibe-d/vibe.d/issues/2673 The code is a "simplification" of something more complex (Special wrappers for **Null | T**, **Undefined | T** and **Undefined | Null | T** with some functional stuff for match! and null-safe access (well, trying to: It's really complex and I'm not enought experienced). I Tried to base my solution in SumType, but I didn't know how to add the required fromRepresentation/toRepresentation methods for custom serialization/deserialization...
Re: int | missing | absent
On Monday, 27 June 2022 at 23:05:46 UTC, Steven Schveighoffer wrote: ... Maybe you can provide an example, and there may be a solution that you haven't thought of. -Steve I first posted this "issue" to vibe-d: https://github.com/vibe-d/vibe.d/issues/2673
Re: int | missing | absent
On Wednesday, 22 June 2022 at 01:09:22 UTC, Steven Schveighoffer wrote: On 6/2/22 9:24 AM, bauss wrote: I feel it's too loose to make a best effort, and leave the rest up to initial values, or just ignore possibly important information during parsing. -Steve May be for your case Steve. I need to represent in a "typed" way complex structures where some properties can be "undefined" (not present in json) and where null value is a valid value (and not the same that "undefined" ones)... basically, the algebraic type Undefined | Null | T It isinefficient in memory terms (because D offers only "structs", not the Typescript object equivalent where properties accepts to be not present nativelly as part of the type definition) But it is, in my opinion, a needed feature: What if you want to "patch" an entity or query an entity requiring only some of the properties?... I don't want to build results using Json objects... D is typed language and results should be built in a rich typed structure (like: {id:"1324123", name:"peter", age:18} or {id:"1234123", age:18 } **validated by compiler**. When implementing rich REST services (with some complexity), undefined native management is a must (and not the same than null management). I am currently using vibe-d json and the way it manages @optional forces me to write custom serialization for all entities (to properly manage undefined vs null)... it is anoying!!!
Re: Static Initialization of Structs syntax
On Wednesday, 22 June 2022 at 09:41:55 UTC, Antonio wrote: I'm so sorry, I know that the above example doesn't work: ```d main(){ Struct PersonDTO { string name; string surname; } void create(PersonDTO personData){ // ... } create( {name: "Peter", surname: "Ustinov"} ); } ``` -Is it there any alternative to initialize "inline" de struct (using the name:value syntax for the properties) without declaring an intermediate variable? Thanks Antonio I see now: DIP 1033 will solve this (i.e., using named arguments in struct constructor... similar to how dart/flutter works)
Static Initialization of Structs syntax
I'm so sorry, I know that the above example doesn't work: ```d main(){ Struct PersonDTO { string name; string surname; } void create(PersonDTO personData){ // ... } create( {name: "Peter", surname: "Ustinov"} ); } ``` -Is it there any alternative to initialize "inline" de struct (using the name:value syntax for the properties) without declaring an intermediate variable? Thanks Antonio
Re: int | missing | absent
On Thursday, 2 June 2022 at 13:24:08 UTC, bauss wrote: On Thursday, 2 June 2022 at 08:27:32 UTC, Antonio wrote: JSON properties can be - a value - null - absent What's the standard way to define a serialziable/deserializable structs supporting properties of any of this 4 kinds?: * int * int | null * int | absent * int | null | absent Whats the best library to manage this JSON requirements? (all the 4 cases)? Thanks null and absent should be treated the same in the code, it's only when serializing you should define one or the other, if you need to have null values AND absent values then attributing accordingly is the solution. The main problem is when you need to use DTO struct that "patches" data (not all the data) and absent vs null discrimination is really mandatory. A good approximation could be using SumTypes (what in Typescript or Scala is named Union Types...), an incredible example of D template power that could be used in Json serialization/deserialization without the need of custom properties attributes. Here an example of how to define DTOs discriminating absent (Undefined in javascrip) and null. i.e. ```d import std.sumtype: SumType, match; import std.datetime.date: Date; void main() { struct Undefined {} struct Null {} struct PersonPatchDTO { SumType!(long) id; SumType!(Undefined, string ) name; SumType!(Undefined, string, string[]) surname; SumType!(Undefined, Null, Date) birthday; SumType!(Undefined, Null, long) partner_id; } auto patchPerson(PersonPatchDTO patch){ import std.stdio: writeln; writeln( "Patching person in database ", patch ); } // This should come from a JSON deserialization; PersonPatchDTO patch = { id:12334, partner_id: Null() }; patchPerson(patch); } ``` Or the typical upset operation some people love to do ```d void main(){ ... struct PersonUpsetDTO { SumType!(Undefined, long) id; SumType!(Undefined, string ) name; SumType!(Undefined, string, string[]) surname; SumType!(Undefined, Null, Date) birthday; SumType!(Undefined, Null, long) partner_id; } auto upsetPerson(PersonUpsetDTO patch){ import std.stdio: writeln; patch.id.match!( (long l) => writeln("Updating person with id ", l), (_) => writeln("Creating a new person") ); } ... } ``` D ha not "union types" native support, but SumType is a nice substitution (with some overhead in generated code). **Problems?** - It is not the "standard" way expected by D Json serializers/deserializers. It requires a custom one - May be it's hard to inspect with debugger (I haven't tried yet)
Re: destroy and @safe
On Tuesday, 21 June 2022 at 16:20:32 UTC, Antonio wrote: My code starts to be a @safe/@trusted mess (because external libraries). The only solution I have is to "wrap" them or to trust all code by default (I'm using vibe.d that forces @safe code) Only as a comment: I can remember now when dart/flutter incorporated "sound null safety" and most of the third-party libraries where ported by authors... everybody assumed this will be the way of. D @safe "optional" adoption is a problem As a personal advice, I would change the scoring system of the packages to penalize when they are not "safe" Reading this I realize that the tone is out of place (especially because of the great disinterested effort behind the code of these libraries and the level of example they provide to those of us who are interested in the language). My apologies.
Re: destroy and @safe
On Tuesday, 21 June 2022 at 15:14:43 UTC, Steven Schveighoffer wrote: You delegate doesn't seem to be marked @safe as well. Thanks a lot Steve, I didn't found a way (or example) to specify the delegate must be @safe until I have found vibe.d.db.postgress implementation (that you maintain :-)
Re: destroy and @safe
On Tuesday, 21 June 2022 at 15:13:36 UTC, Paul Backus wrote: If the destructor is `@system`, then the only way to call `destroy` in `@safe` code is to (1) determine the conditions necessary to call the destructor without violating memory safety, (2) ensure that those conditions are met (using compile time and/or runtime checks), and (3) wrap the call to `destroy` in a `@trusted` function. Since step (1) depends on the specific details of the destructor you want to call, I can't give any more specific advice unless you show a complete example that includes the destructor. Thanks Paul. The problem appears when destroying a dpq2 query result object (not @safe). I supose I can accept postgres PGClean(result) is safe "enought". My code starts to be a @safe/@trusted mess (because external libraries). The only solution I have is to "wrap" them or to trust all code by default (I'm using vibe.d that forces @safe code) Only as a comment: I can remember now when dart/flutter incorporated "sound null safety" and most of the third-party libraries where ported by authors... everybody assumed this will be the way of. D @safe "optional" adoption is a problem As a personal advice, I would change the scoring system of the packages to penalize when they are not "safe"
destroy and @safe
I'm using explicitly destroy!false(obj) for a "deterministic" resources release. I replicate the c# "using" pattern, or the python "with" pattern with my own "use" template supposing object are RAII i.e.: ```d Item[] items = query("...").use( (Answer a) => a.rangify.map!(rowToItem).array() ); ``` The problem: "use" can't be @safe because it contains a call to "destroy". For better understanding of the idea, I include the "use" template code ```d R use(R, T)(T obj, R delegate(T) fT) { scope (exit) destroy!false(obj); return fT(obj); } ``` What's the way to ensure @safe using destroy? (if possible)
Re: Enforce not null at compile time?
On Monday, 20 June 2022 at 19:08:32 UTC, max haughton wrote: On Monday, 20 June 2022 at 17:48:48 UTC, Antonio wrote: Is there any way to specify that a variable, member or parameter can't be null? You can use an invariant if it's a member of an aggregate but be warned that these are only checked at the boundaries of public member functions. I'm using preconditions when calling functions ```d auto readByCredentiasl(CredentialsDTO credentials) in (credentials !is null) in (credentias.username !is null) ... { ... } ``` But it's runtime validation, not formally validated by compiler.
Enforce not null at compile time?
Is there any way to specify that a variable, member or parameter can't be null?
Re: UFCS limit
On Friday, 17 June 2022 at 12:26:05 UTC, Antonio wrote: UFCS vs Functional curring... nice battle :-) **UFCS & CFTE** vs **Functional currying**... nice battle :-)
Re: UFCS limit
On Friday, 17 June 2022 at 01:04:28 UTC, Paul Backus wrote: On Thursday, 16 June 2022 at 23:59:06 UTC, Antonio wrote: Is it there any way to apply UFCS on the returned method in the same expression? Nope. The way UFCS works is that allows you to call free functions using member-function syntax, and member-function syntax is always `object.memberName`, so UFCS only works for functions that have a name, not anonymous functions. Lets tray with a name :-) ```d auto doSomething(string text) { return (string text2) { import std.stdio; writeln(text,",",text2); }; } void main() { auto doHello = doSomething("Hello"); doHello("X"); "X".doHello(); } ``` Error: onlineapp.d(16): Error: no property `doHello` for type `string` It's true... the favomous "Rationale: Local function symbols are not considered by UFCS to avoid unexpected name conflicts." (I consider it absurd... but I'n no-one) Well lets try another possibility taking in account the power of CTFE ```d auto doSomething(string text) { return (string text2) { import std.stdio; writeln(text,",",text2); }; } auto doHello = doSomething("Hello"); void main() { doHello("X"); "X".doHello(); } ``` Error: onlineapp.d(3): Error: closures are not yet supported in CTFE :-/ UFCS vs Functional curring... nice battle :-)
UFCS limit
```d auto doSomething(string text) { return (string text2) { import std.stdio; writeln(text,",",text2); }; } void main() { doSomething("Hello")("X"); "X".doSomething("Hello")(); } ``` Compiler error: ``` ... onlineapp.d(13):expected 1 argument(s), not 2 ``` I tried with some syntax change: ```d void main() { doSomething("Hello")("X"); (doSomething("Hello"))("X"); // it works "X".(doSomething("Hello"))(); // fails!!! } ``` ```onlineapp.d(14): Error: identifier or `new` expected following `.`, not `( Is it there any way to apply UFCS on the returned method in the same expression?
Re: map! evaluates twice
On Friday, 10 June 2022 at 20:47:14 UTC, Steven Schveighoffer wrote: On 6/10/22 4:33 PM, Antonio wrote: ... `map` calls the lambda for each call to `front`. If you want a cached version, use `cache`: Thank you very much, Steve
map! evaluates twice
When mapping and filtering, the last mapped element is evaluated twice... Is it the expected behaviour? ```d void main() { import std.algorithm, std.stdio; [1,2,3,4,5]. map!((x){ writeln("mapping ", x); return x; }). filter!(x=>x>2). front. writeln(); } ``` Output ``` mapping 1 mapping 2 mapping 3 mapping 3 3 ```
Re: Range to Nullable conversion
On Friday, 10 June 2022 at 18:00:20 UTC, Paul Backus wrote: On Friday, 10 June 2022 at 17:22:53 UTC, Antonio wrote: Can this code be written as a **simple** expression? (without having to write helper methods). ```d import std.range, std.typecons; Nullable!(ElementType!R) maybeFront(R)(auto ref R r) if (isInputRange!R) { if (r.empty) return typeof(return)(); else return nullable(r.front); } unittest { int[] a = [1, 2, 3]; int[] b; assert(a.maybeFront == nullable(1)); assert(b.maybeFront.isNull); } ``` Nice (and simple) helper method. Thank you Paul
Re: Range to Nullable conversion
On Friday, 10 June 2022 at 17:37:13 UTC, Ali Çehreli wrote: On 6/10/22 10:22, Antonio wrote: > Is there any alternative to ***range front*** that returns a Nullable > (i.e. **frontAsMonad** or **frontAsNullable**)? import std; // Spelling? :) auto nullablelize(R)(R range) { ... } void main() { // Wow! We can take 10 elements without error. :) writeln(iota(5) .filter!(i => i % 2) .nullablelize .take(10)); } Ali That's cheating :-p... you used a helper method+structure. Nice example, Thank you Ali.
Range to Nullable conversion
Is there any alternative to ***range front*** that returns a Nullable (i.e. **frontAsMonad** or **frontAsNullable**)? I'm using Vibe.d and Nullable is the standard way to return an optional element: ```d @safe Nullable!Item getItem(int _id) { import std.algorithm : filter; with (items.filter!(item => item.id == _id)) { if (empty) return Nullable!Item.init; else return front.nullable; } } ``` Can this code be written as a **simple** expression? (without having to write helper methods).
int | missing | absent
JSON properties can be - a value - null - absent What's the standard way to define a serialziable/deserializable structs supporting properties of any of this 4 kinds?: * int * int | null * int | absent * int | null | absent Whats the best library to manage this JSON requirements? (all the 4 cases)? Thanks
Re: UFCS doubt
On Thursday, 8 July 2021 at 22:31:49 UTC, Dennis wrote: On Thursday, 8 July 2021 at 22:24:26 UTC, Antonio wrote: I supossed that ```mfp(c,20)``` and ```c.mfp(20)``` should be equivalent because UFCS in second example, but it is not... why? UFCS does not work for nested functions. Functions declared in a local scope are not found when searching for a matching UFCS function. ... Rationale: Local function symbols are not considered by UFCS to avoid unexpected name conflicts. See below problematic examples. https://dlang.org/spec/function.html#pseudo-member Thanks. I read the example and the assumption of "name conflict" does not seem to be justified (from my point of view) i.e. Without dot notation, this example must fail ``` int front(int[] arr) { return arr[0]; } void main() { int[] a =[1,2,3]; auto front = 1; // front is now a variable auto y = front(a); // Error, front is not a function } ``` Changing to y = a.front() should not change the behavior (it is only a notation change )... but it does!!! ``` int front(int[] arr) { return arr[0]; } void main() { int[] a =[1,2,3]; auto front = 1; // front is now a variable auto y = a.front() // NO ERROR!!! } ``` "It works as described in the manual, not as expected" (from MySQL haters club :-p) .
UFCS doubt
In this example (extracted from https://digitalmars.com/articles/b68.html), this works: ``` class C { int a; int foo(int i) { return i + a; } } auto mfp = (C self, int i)=>self.foo(i); void main(){ auto c = new C; assert( c.mfp(20)==20); } ``` but this fails ``` class C { int a; int foo(int i) { return i + a; } } void main(){ auto mfp = (C self, int i)=>self.foo(i); auto c = new C; assert( c.mfp(20)==20); } ``` onlineapp.d(9): Error: no property `mfp` for type `onlineapp.C` I supossed that ```mfp(c,20)``` and ```c.mfp(20)``` should be equivalent because UFCS in second example, but it is not... why?
github copilot and dlang
Has someone tried github copilot (https://copilot.github.com/) with dlang? Access to the preview could be requested and, I think, main dlang team members could bypass the waitlist easily. I suspect that the "low" volume of dlang code (used to train OpenAI) compared to other languages could impact in the support (if there is any). Anyway, it could be really interesting to see how Copilot faces templates, traits, ...
Re: Fix gtkD api display
On Thursday, 10 August 2017 at 14:59:52 UTC, Adam D. Ruppe wrote: On Thursday, 10 August 2017 at 14:55:06 UTC, Mike Wey wrote: [...] Oh, I see. My generator lists them on the index, but doesn't recreate it each time, it just links. For example: http://dpldocs.info/experimental-docs/gtk.ApplicationWindow.ApplicationWindow.html it lists inherited members again, but not all their docs. [...] kewl [...] It is a lot easier to link to individual pages from the outside which means search is more reliable, the back button works, stuff like that. Hi, The way valadoc.org exposes the docs makes them very easy to read and find things (at least for me). A. Corbi