Fortran 2003 supports data polymorphism by using class, like:
subroutine excute(A)
class(*) :: A
select type (A)
class is ()
...
type is ()
...
end select
end subroutine
My question is: if I need to call this subroutine a huge amount of times, whether it will slow the code down because of the SELECT statement?
SELECT TYPE is typically implemented by the descriptor for the polymorphic object (CLASS(*) :: A here) having a token or pointer or index of similar that designates the dynamic type of the object. Execution of the select type is then like a SELECT CASE on this token, with the additional complication that non-polymorphic type guards (TYPE IS) are matched in preference to polymorphic guards (CLASS IS).
There is some overhead associated with this construct. That overhead is more than if the code did nothing at all. Then again, code that does nothing at all is rarely useful. So the real question is whether the use of SELECT TYPE is better or worse execution speed wise to some alternative approach that provides the necessary level of functionality (which might be less than the full functionality that SELECT TYPE provides) that your code needs. To answer that, you would need to define and implement that approach, and then measure the difference in speed in a context that's relevant to your use case.
As indicated in the comments, an unlimited polymorphic entity is essentially a type safe way of storing something of any type. In this case, SELECT TYPE is required at some stage to be able to access the value of the stored thing. However, this is only a rather specific subset of F2003's support for polymorphism. In more typical examples SELECT TYPE would not be used at all - the behaviour associated with the dynamic type of an object would be accessed by calling overridden bindings of the declared type.
Related
We have a table with 2 top level columns of type 'struct' - one is a 'before', and an 'after' image. The struct schemas are non trivial - nested, with arrays to a variable depth. The are sent to us from replication, so the schemas are always the same (but the schemas of course can be updated at some point, but always together)
Objective is for the two input structs, to return 2 struct 'diffs' of the before and after with only fields that have changed - essentially the 'delta' diff of the changes produce by the replication source. We know something has changed, but not 'what' since we get the full before and after image. this raw data lands in BQ and is then processed from there but need to determine the more granular change for high order BQ processing.
The table schema is very wide (1000's of leaf fields), and the data populated fairly spare (so alot of nulls will be present on both sides of the snapshot) - so would need to be performant as best as possible when executing over 10s of millions of rows.
All things are nullable for maximum flexibility.
So change could look like:
null -> value
value -> null
valueA -> valueB
Arrays:
recursive use of above for arrays of structs, ordering could be relaxed if that makes it easier?
It might not be possible.
Ive not attempted this yet as it seems really difficult so am looking to the community boffins for some support for this. I feel the arrays could be difficult part. There is probably an easy way perhaps in Python I dont or even doing some JSON conversion and comparison using JOSN tools? It feels like it would be a super cool feature built in to BQ as well, so if can get this to work, will add a feature request for it.
Id like to have a SQL UDF for reuse (we have SQL skills not python, although if easier in python then thats ok), and now with the new feature of persistent SQL UDFs, this seems the right time to ask and test the feature out!
sql
def struct_diff(before Struct, after Struct)
(beforeChange, afterChange) - type of signature but open to suggestions?
It appears to be really difficult to get a piece of reusable code. Since currently there is no support for recursive functions for SQL UDF, you cannot use a recursive approach for the nested structs.
Although, you might be able to get some specific SQL UDF functions depending on your array and structs structures. You can use an approach like this one to compare the structs.
CREATE TEMP FUNCTION final_compare(s1 ANY TYPE, s2 ANY TYPE) AS (
STRUCT(s1 as prev, s2 as cur)
);
CREATE TEMP FUNCTION compare(s1 ANY TYPE, s2 ANY TYPE) AS (
STRUCT(final_compare(s1.structA, s2.structA))
);
You can use UNNEST to work with arrays, and the final SQL UDF would really depend on your data.
As #rtenha suggested, Python could be a lot easier to handle this problem.
Finally, I did some tests using JavaScript UDF, and it was basically the same result, if not worst than SQL UDF.
The console allows a recursive definition of the function, however it will fail during execution. Also, javascript doesn't allow the ANY TYPE data type on the signature, so you would have to define the whole STRUCT definition or use a workaround like applying TO_JSON_STRING to your struct in order to pass it as a string.
I try to compile all ways that ABAP provides to declare variables, types, and alike, including obsolete and acrane syntax variants. So, for example, I would include FIELD-GROUPS in the list but not the declaration of classes. My current list is as follows. Did I miss anything?
statements declaring variables
DATA-like declarative statements
DATA (excluding DATA BEGIN OF COMMON PART), STATICS, PARAMETER, PARAMETERS, CONSTANTS
FIELD-SYMBOLS
inline declarations
actual parameters of procedures
FORM (subroutine), FUNCTION, METHOD
other variable declaring statements
RANGES, SELECT-OPTIONS: Are there further?
statements declaring types
TYPES
other statements
DATA BEGIN OF COMMON PART
not a declarative statement in itself but a way to group further DATA statements.
FIELD-GROUPS
declares an extract dataset, which is not part of the ABAP type concept for data types and data objects
Disclaimer: We are writing a tool in Java that parses and transforms ABAP code. In particular, we have no intention to write new ABAP code. But instead, our tool has to handle all of ABAP, even obsolete statements and obscure syntax variants. Furthermore, I'd like to mention that I'm not an ABAP expert.
To complete your list, you may add these ones (partially taken from the ABAP doc - obsolete declarations) :
TABLES
NODES
LOCAL
FIELDS
CLASS-DATA
ALIASES for attributes (not really a declaration, but it adds a new name for the given attributes)
CONTROLS
There are the auxiliary variables inside constructor expressions (FOR aux..., FOR , LET ...)
Programs have predefined types and variables (SY, SCREEN and so on; I feel you can extract all of them from the "implicit system includes" but you must know those includes).
Eventually consider the statements inside macros, either internal (DEFINE) or external (table TRMAC).
There are statements which correspond to internal includes:
TYPE-POOLS (was mandatory before 7.02)
INFOTYPES
CONTEXTS
Of course, there are also all the DDIC types.
I don't know if you want to scan also CREATE DATA (for tools like abstract interpreters).
PS: you say that common parts are not real declarative statements, that's wrong, they declare data objects, plus an additional "sharing feature".
Using the SQL type provider in FSharp.Data with MSFT SQL Server, I declare the type:
type dbSchema = FSharp.Data.TypeProviders.SqlDataConnection<"Data Source=DESKTOP-5\SQLEXPRESS;Initial Catalog=Data;Integrated Security=True;MultipleActiveResultSets=True;">
outside of any module, along with most of my other types (following a suggestion to declare types outside of modules to avoid nested classes). I really wouldn't know, but assume that it's so far so good.
Where I'm wondering how to arrange things is in using the type, with eg:
use db = dbSchema.GetDataContext()
db.DataContext.ExecuteCommand(sqlCreateTableStmt a b c)
My upload process goes through lists of lists and functions calling functions. And I don't know what the pros and cons are of where to declare use db. It could be re-done locally in each function, or "globally" outside any module, or in the first, top-level function and passed along from function to function as a parameter. Or some combination.
Hopefully that's enough of a question to be worthwhile. Right now I have a use declaration in each function. Not passing it ever. In some places one function declares use db and calls another function that declares use db again. I don't know if there's overhead in making or managing these connections. Or whatever else to worry about.
Thanks in advance.
I have an ABAP class method, say, select_something. select_something has an exporting parameter, say, et_result. et_result is of type standard table because the type of et_result cannot be determined until runtime.
The method sometimes gives a short dump saying With ABAP/4 Open SQL array select, the output table is too small at "select * into table et_result from (lv_tablename) where..."
Error analysis:
......in this particular case, the database table is 3806 bytes wide, but the internal table is only 70 bytes wide.
I tried "any table" too and the error is the same.
You could return a data reference. Your query will no longer fail, and you can assign the data to a correctly typed field symbol afterwards.
" Definition
class-methods select_all
importing
!tabname type string
returning
value(results) type ref to data.
...
...
" Implementation
method select_all.
data dref type ref to data.
create data dref type standard table of (tabname).
field-symbols <tab> type any table.
assign dref->* to <tab>.
select * from (tabname) into table <tab>.
get reference of <tab> into results.
endmethod.
Also, I agree with #vwegert that dynamic queries (and programming for that matter) should be avoided when possible.
What you're trying to do looks horribly wrong on many levels. NEVER use SELECT FROM (whatever) unless someone points a gun at your head AND the door is locked tight. You'll loose every kind of static error checking the system might be able to provide you with. For example, the compiler will no longer be able to tell you "Hey, that table you're reading from is 3806 bytes wide." It simply can't tell, even if you use constants. You'll find that out the hard way, producing short dumps, especially when switching between unicode and NUC systems, quite likely some in production systems. No fun.
(Actually there are a few - very very VERY few - good uses for dynamic table names in the SELECT statement. I need them about once every two to three years, and I code quite a lot weird stuff. Just avoid them wherever you can, even at the cost of writing more code. It's just not worth the trouble fixing broken stuff later.)
Then, changing the generic formal parameter type does not do anything to the type of the actual parameter. If you pass a STANRDARD TABLE OF mandt WITH DEFAULT KEY to your method, that table will have lines of 3 characters. It will be a STANDARD TABLE, and as such, it will also be an ANY TABLE, and that's about it. You can twist the generic types anywhere you like, there's no way to enforce correctness using generic types the way you use them. It's up to the caller to make sure that all the right types are used. That's a bad way to fly.
First off, I agree with vwegert's response, try to avoid dynamic sql selections if you can
That said, check the short dump. If the error is an exception class, you can wrap the SELECT statement in a try/catch block and at least stop it from dumping.
You can also try "INTO CORRESPONDING FIELDS OF TABLE et_result". If ET_RESULT is dynamic, you might have to cast it into the proper structure using RTTS. This might give you some ideas...
Couldn't agree more to vwegert, but if there is absolutely no other way (and there usually is) of performing your task than using dynamic select statements and dynamically typed parameters, do some checks on the type of the table and the parameter at runtime.
Use CL_ABAP_TYPEDESCR and its subclasses to do so.
This way, you can handle errors at runtime without your program dumping,
But as vwegert said, this dynamic stuff is pure evil and will most certainly break at some point during runtime. Adding the necessary error handling will most likely be a lot more work and a lot harder than redesigning your code to none dynamic SQL and typed parameters
I see it used a lot in context of data. From ScottGu's post:
One of the really powerful
capabilities provided by LINQ and
query syntax is the ability for you to
define new classes that are separate
from the data being queried, and to
then use them to control the shape and
structure of the data being returned
by the query.
What does he mean when he refers to shape of the data?
I think these are informal terms, and the definitions are subjective. I would use "shape" to refer to how the object fits in with other objects in the system. (Compare "surface area", which is a rough (no pun intended :-) measure of the complexity of the object's interface.) I'd use "structure" to refer to how the object is designed and implemented internally.
Hence you can have classes that have a good "shape", but a structure like crepe paper. That's probably easier to refactor than the other way around: a poor shape, but good implementation. (I'm sure some folks would question whether the latter is even possible.)
consider shape to be the objects "api" while the structure is it's internal implementation. In a well designed system the shape will remain static while the structure may change significantly.
The shape is any spatial attributes (especially as defined by outline) of the object, whereas the structure is the manner of construction of the object and the arrangement of its parts. Of course, that can apply to any type of object. :)
Generally, I would consider the shape of an a class to be the public methods and properties that the class offers. The structure would be the internal constructs and representation used. In the context of the quoted material, I would take it to mean that by allowing one to define the return type of a query using anonymous or alternate named classes, you can redefine the data returned by query, constraining and transforming its shape from the original data source.
For example, say you have a user table that is related to a contacts table. Using LINQ and anonymous class as the selection, you can return a user with primary contact object without having to define a particular view; using only LINQ.
var userWithContact = from u in db.Users
select new
{
Name = u.Name,
Address = u.Contacts
.Where( c => c.Type = "self" ).First().Address
};