Forum > Suggestions

Custom type for Nil

<< < (10/10)

PascalDragon:

--- Quote from: Warfley on March 16, 2022, 10:06:04 am ---
--- Quote from: PascalDragon on March 16, 2022, 08:33:30 am ---In my opinion lambda A, B as A.ID - B.ID is more Pascal (and that is a syntax I had already thought about adding once anonymous functions are ready, but other devs don't agree here). However the problem is that this requires type inference and that is a concept that as such does not exist in Pascal or the compiler, thus making this a rather complex functionality.

--- End quote ---
Already thought that this might pose a problem, but such a feature might also be useful for generics, to deduce generic types:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---generic function foo<T>(val: T);... foo<>(24); // instead of foo<Integer>(24)
--- End quote ---

This - which is called implicit specializations - is already in development (the syntax is without any <> (or specialize) at all, cause the compiler might pick a non-generic routine as well) and is much less of a problem then the type inference required for such lambda expressions. This is because for a lambda expression the compiler would essentially need to parse the whole thing blindly, then determine which function is called (if the lambda is a parameter there might be multiple suitable overloads after all) and then it would need to recheck the lambda to determine whether the generated code would fit. For an implicit specialization the compiler only needs to check whether the given parameters would satisfy any of the suitable generic routines (or maybe even a non-generic).


--- Quote from: Warfley on March 16, 2022, 10:06:04 am ---
--- Quote from: PascalDragon on March 16, 2022, 08:33:30 am ---Also I don't know whether this would be some code I'd like to read:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---TList<Integer>.Combine(list1, list2, +);// orspecialize TList<Integer>.Combine(list1, list2, @+);
--- End quote ---
I thought more about something like

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---TList<Integer>.Combine(list1, list2, operator Integer.Add);// orTList<Integer>.Combine(list1, list2, operator Add);Or something similar. I actually like wordy syntax more than just throwing symbols there, and at least for mode delphi the operators already have names (this would also make disambigouagtion between binary and unary operator - easier)

--- End quote ---

In mode ObjFPC operators are not named, they are symbols. But I agree in so far that a keyword operator might make things look nicer. In mode ObjFPC:


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---specialize TList<Integer>.Combine(list1, list2, @operator +);
However consistency would also dictate then that code like this is possible:


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---var  i1, i2, i3: LongInt;begin  i3 := operator +(i1, i2);end.

Warfley:

--- Quote from: PascalDragon on March 17, 2022, 01:07:27 pm ---
--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---specialize TList<Integer>.Combine(list1, list2, @operator +);
--- End quote ---
I think this looks neat tbh

--- Quote from: PascalDragon on March 17, 2022, 01:07:27 pm ---This - which is called implicit specializations - is already in development (the syntax is without any <> (or specialize) at all, cause the compiler might pick a non-generic routine as well) and is much less of a problem then the type inference required for such lambda expressions. This is because for a lambda expression the compiler would essentially need to parse the whole thing blindly, then determine which function is called (if the lambda is a parameter there might be multiple suitable overloads after all) and then it would need to recheck the lambda to determine whether the generated code would fit. For an implicit specialization the compiler only needs to check whether the given parameters would satisfy any of the suitable generic routines (or maybe even a non-generic).

--- End quote ---
With regards to this, and this also ties in with the restrictions for generics discussed earlier in this thread, for some time I now had one thing in mind that kinda annoyed me a little on the usability of generics, and that is the distinction between classes, objects and records.

Because with a lot of use-cases you do not need to care if your generic argument is an advanced record, object or class, as long as it provides the suitable interface:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---generic procedure WriteData<T>(constref AData: T);begin  WriteLn(AData.ToString);end;This works for any Type that provides .ToString. But there is one big difference, that is if you transfer ownership the the generic object or function, it needs to know if it has to call Free, done or simply let the finalisation of the compiler do the rest. Usually I solve this with another additional generic parameter:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---generic procedure WriteDataAndFree<T, TFinalizer>(constref AData: T);begin  WriteLN(AData.ToString);  TFinalizer.FinalizeData(AData);end;With three "partial" specializations:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---generic procedure WriteDataAndFreeClass<T>(constref AData: T);begin  specialize WriteDataAndFree<T, specialize TClassFinalizer<T>>(AData); // where TClassFinalizer.FinalizeData calls Free on Tend;generic procedure WriteDataAndFreeObject<T>(constref AData: T);begin  specialize WriteDataAndFree<T, specialize TObjectFinalizer<T>>(AData); // where TObjectFinalizer.FinalizeData calls Done on Tend;generic procedure WriteDataAndFreeRecord<T>(constref AData: T);begin  specialize WriteDataAndFree<T, TNoopFinalizer>(AData); // where TNoopFinalizer.FinalizeData does nothing as the compiler will add the finalization codeend;What would be much nicer would be the following:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---generic procedure WriteDataAndFree<T: TObject>(constref AData: T);begin  specialize WriteDataAndFree<T, specialize TClassFinalizer<T>>(AData); // where TClassFinalizer.FinalizeData calls Free on Tend;generic procedure WriteDataAndFree<T: object>(constref AData: T);begin  specialize WriteDataAndFree<T, specialize TObjectFinalizer<T>>(AData); // where TObjectFinalizer.FinalizeData calls Done on Tend;generic procedure WriteDataAndFree<T: Record>(constref AData: T);begin  specialize WriteDataAndFree<T, TNoopFinalizer>(AData); // where TNoopFinalizer.FinalizeData does nothing as the compiler will add the finalization codeend;And letting the compiler figure out what to call. One area in particular is for enumerators, because there the programmer does probably not even know what kind of enumerator there is (most enumerators encountered in the wild are classes, but I have already seen and made records being enumerators)
So considering the following map function:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---generic function Map<TFrom, TTo, TEnumerator>(const Enumerator: TEnumerator; MapFunction: specialize TMapFunction<TFrom, TTo>): specialize TMappingIterator<TFrom, TTo>;begin  Result := specialize TMappingIteratorClass<TFrom, TTo, TEnumerator>.Create(Enumerator, MapFunction); // inherits from TMappingIterator to be applicable to a specific enumeratorend; // usage with implicit specializationfor str in Map(MyIntegerList.GetEnumerator, @IntToStr) do  ...Where TMappingIterator would be an iterable object (i.e. returns Self on GetEnumerator and has MoveNext and Current), and would apply map to each element. Currently this would need 3 functions MapObject, MapClass and MapRecord, which generally is not that bad (which calls the corresponding TMapIterator for either Obejcts, Classes or Records), but the user needs to know what kind of type the Enumerator is, which is somethign I usually do not know for most collections.
Also something as described above would allow this:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---generic function MapEnumerator<TFrom, TTo, TEnumerator: TObject>(const Enumerator: TEnumerator; MapFunction: specialize TMapFunction<TFrom, TTo>): specialize TMappingIterator<TFrom, TTo>;generic function MapEnumerator<TFrom, TTo, TEnumerator: Object>(const Enumerator: TEnumerator; MapFunction: specialize TMapFunction<TFrom, TTo>): specialize TMappingIterator<TFrom, TTo>;generic function MapEnumerator<TFrom, TTo, TEnumerator: Record>(const Enumerator: TEnumerator; MapFunction: specialize TMapFunction<TFrom, TTo>): specialize TMappingIterator<TFrom, TTo>; generic function Map<TFrom, TTo, TCollection>(const Collection: TCollection; MapFunction: specialize TMapFunction<TFrom, TTo>): TMappingIterator<TFrom, TTo>;begin  MapEnumerator(Collection.GetEnumerator, MapFunction);end;Which would allow the following construct:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---for str in Map(MyIntegerList, @IntToStr) do  ...Working for every kind of collection, no matter how they implement their enumerator. Which I think would be really neat.

Also nice would be to also have a "fallback" declaration:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---generic procedure Test<T: TObject>; // chosen for all classesgeneric procedure Test<T: Object>; // chosen for all objectsgeneric procedure Test<T>; // chosen if nothing of the above matched But this is basically C++ SFINAE, which, while the idea is nice, devolved through the use of the community to one of the most confusing paradigms I have ever seen in software development

Navigation

[0] Message Index

[*] Previous page

Go to full version