<metaproperty="description"content="TL (Type Language) serves to describe the used system of types, constructors, and existing functions. In fact, the combinator…">
<metaproperty="og:title"content="TL Language">
<metaproperty="og:image"content="">
<metaproperty="og:description"content="TL (Type Language) serves to describe the used system of types, constructors, and existing functions. In fact, the combinator…">
<divid="dev_page_content"><p>TL (Type Language) serves to describe the used system of types, constructors, and existing functions. In fact, the combinator description format presented in <ahref="/mtproto/serialize">Binary Data Serialization</a> is used.</p>
<p>See also: </p>
<ul>
<li><ahref="/mtproto/TL-polymorph">Polymorphism in TL</a></li>
</ul>
<p>Advanced topics: </p>
<ul>
<li>
<p><ahref="/mtproto/TL-dependent">Dependent types in TL</a></p>
</li>
<li>
<p><ahref="/mtproto/TL-formal">Formal description of TL</a></p>
</li>
<li>
<p><ahref="/mtproto/TL-combinators">Formal description of TL combinators</a></p>
<p>A TL program usually consists of two sections separated by keyword <code>---functions---</code>. The first section consists of declarations of built-in types and aggregate types (i.e. their constructors). The second section consists of the declared functions, i.e. functional combinators.</p>
<p>Actually, both the first and second sections consist of combinator declarations, each of which ends with a semicolon. However, the first section contains only constructors, while the second section only involves functions. Each combinator is declared using a “combinator declaration” in the format explained above. However, the combinator number and field names may be explicitly assigned.</p>
<p>If additional type declarations are required after functions have been declared, the keyword (section divider) <code>---types---</code> is used. Furthermore, a functional combinator may be declared in the type section if its result type begins with an exclamation point (in fact, when the function section is interpreted, this exclamation point is added automatically).</p>
<p>To explicitly define 32-bit names of combinators, a hash mark (#) is added immediately after the combinator’s name, followed by 8 hexadecimal digits.</p>
<p>Composite constructions like <code><namespace_identifier>.<constructor_identifier></code> and <code><namespace_identifier>.<Type_identifier></code> can be used as constructor- or type identifiers. The portion of the identifier to the left of the period is called the <em>namespace</em>. Moreover, the rule about a first uppercase letter in type identifiers and lowercase letter in constructor identifiers applies to the part of the construction after the period. For example, <code>auth.Message</code> would be a type, while <code>auth.std_message</code> would be a constructor.</p>
<p>Namespaces do not require a special declaration.</p>
<p>In this case, the <code>user</code> constructor has been explicitly assigned a number (0xd23c81a3); In fact, this was not necessary, since this value is the CRC32 of the string <code>"user id:int first_name:string last_name:string = User"</code>, which would have been used by default.</p>
<p>Special constructors are not required for Vector int, Vector User, Vector Object, etc. -- the same universal constructor can be used everywhere:</p>
<pre><code>vector#1cb5c415 {t:Type} # [ t ] = Vector t;</code></pre>
<p>Note that when the <code>getUsers (Vector int) = Vector User;</code> constructor number is calculated, the CRC32 of the string "getUsers Vector int = Vector User” is computed (from which all parentheses have been removed).</p>
<p>Notation <code>T0<T1,T2,...,Tn></code> is syntactic sugar for <code>(T0 (T1) (T2) ... (Tn))</code>. For example, <code>Vector<User></code> and <code>(Vector User)</code> are entirely interchangeable.</p>
<h4><aclass="anchor"href="#example-of-an-rpc-query"id="example-of-an-rpc-query"name="example-of-an-rpc-query"><iclass="anchor-icon"></i></a>Example of an RPC query</h4>
<p>Suppose we want to call <code>getUsers([2,3,4])</code>. This query will be serialized into a sequence of 32-bit integers as follows:</p>
<p>Please note that TL serialization yields sequences of 32-bit integers. When it has to be embedded into a byte stream, for example a network packet, each 32-bit integer is represented by four bytes in little-endian order. In this way the above query corresponds to the following byte stream:</p>
<p>Note that in both cases the same universal constructor <code>vector#1cb5c415</code> is used: in the request to serialize the value of type <code>Vector int</code>, and in the serialization of the value of type <code>Vector User</code> in the response. There is no ambiguity because in both cases the type of the value being (de)serialized is known before its (de)serialization begins. For example, after receiving the query, the server sees that the first part is <code>0x2d84d5f5</code>, which corresponds to the combinator <code>getUsers#2d84d5f5 (Vector int) = Vector User</code>. Thus, it is understood that what follows will be a value of type <code>Vector int</code>. After receiving the response to this query, the client knows that it must receive a value of type <code>Vector User</code> and it deserializes the response accordingly.</p></div>
</div>
</div>
</div>
<divclass="footer_wrap">
<divclass="footer_columns_wrap footer_desktop">
<divclass="footer_column footer_column_telegram">
<h5>Telegram</h5>
<divclass="footer_telegram_description"></div>
Telegram is a cloud-based mobile and desktop messaging app with a focus on security and speed.